I'm stuck. I can not get data from server. (server is working 100%). but I got issues with requesting data.
this is minimized code:
import { ApolloClient, InMemoryCache, createHttpLink, ApolloProvider } from '#apollo/client'
import RepositoryList from './RepositoryList'
const httpLink = createHttpLink({
uri: 'http://localhost:4000/graphql',
})
const createApolloClient = () => {
return new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
})
}
const apolloClient = createApolloClient()
export default App = () => {
return(
<ApolloProvider client={apolloClient}>
<RepositoryList />
</ApolloProvider>
)
}
Repository List:
import { useQuery, gql } from '#apollo/client'
const GET_REPOSITORIES = gql`
query {
repositories {
fullName
description
}
}
`
const RepositoryList = () => {
const { data, error, loading } = useQuery(GET_REPOSITORIES)
console.log('data', data) //log: undefined
console.log('error', error) //log: [Error: Network request failed]
console.log('loading', loading) //log: false
return <></>
}
Console gives data undefined and Error is: Network connection failed.
I tried to go on http://localhost:4000/graphql and run query. Everything was working perfectly
Try changing changing http://localhost:4000 by http://10.0.2.2:4000/
const httpLink = createHttpLink({
uri: 'http://10.0.2.2:4000/graphql',
})
Related
I am new to NextJS. I have a page that needs to display real-time data pulled from a Hasura GraphQL backend.
In other non-NextJS apps, I have used GraphQL subscriptions with the Apollo client library. Under the hood, this uses websockets.
I can get GraphQL working in NextJS when it's not using subscriptions. I'm pretty sure this is running on the server-side:
import React from "react";
import { AppProps } from "next/app";
import withApollo from 'next-with-apollo';
import { ApolloProvider } from '#apollo/react-hooks';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { getToken } from "../util/auth";
interface Props extends AppProps {
apollo: any
}
const App: React.FC<Props> = ({ Component, pageProps, apollo }) => (
<ApolloProvider client={apollo}>
<Component {...pageProps}/>
</ApolloProvider>
);
export default withApollo(({ initialState }) => new ApolloClient({
uri: "https://my_hasura_instance.com/v1/graphql",
cache: new InMemoryCache().restore(initialState || {}),
request: (operation: any) => {
const token = getToken();
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : ''
}
});
}
}))(App);
And I use it this way:
import { useQuery } from '#apollo/react-hooks';
import { gql } from 'apollo-boost';
const myQuery = gql`
query {
...
}
`;
const MyComponent: React.FC = () => {
const { data } = useQuery(myQuery);
return <p>{JSON.stringify(data)}</p>
}
However, I would instead like to do this:
import { useSubscription } from '#apollo/react-hooks';
import { gql } from 'apollo-boost';
const myQuery = gql`
subscription {
...
}
`;
const MyComponent: React.FC = () => {
const { data } = useSubscription(myQuery);
return <p>{JSON.stringify(data)}</p>
}
What I've tried
I've tried splitting the HttpLink and WebsocketLink elements in the ApolloClient, like so:
import React from "react";
import { AppProps } from "next/app";
import { ApolloProvider } from '#apollo/react-hooks';
import withApollo from 'next-with-apollo';
import { InMemoryCache } from "apollo-cache-inmemory";
import ApolloClient from "apollo-client";
import { split } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';
import { getToken } from "../util/auth";
interface Props extends AppProps {
apollo: any
}
const App: React.FC<Props> = ({ Component, pageProps, apollo }) => (
<ApolloProvider client={apollo}>
<Component {...pageProps}/>
</ApolloProvider>
);
const wsLink = new WebSocketLink({
uri: "wss://my_hasura_instance.com/v1/graphql",
options: {
reconnect: true,
timeout: 10000,
connectionParams: () => ({
headers: {
authorization: getToken() ? `Bearer ${getToken()}` : ""
}
})
},
});
const httpLink = new HttpLink({
uri: "https://hasura-g3uc.onrender.com/v1/graphql",
});
const link = process.browser ? split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink
) : httpLink;
export default withApollo(({ initialState }) => new ApolloClient({
link: link,
cache: new InMemoryCache().restore(initialState || {}),
}))(App);
But when I load the page, I get an Internal Server Error, and this error in the terminal:
Error: Unable to find native implementation, or alternative implementation for WebSocket!
It seems to me that the ApolloClient is then being generated on the server-side, where there is no WebSocket implementation. How can I make this happen on the client-side?
Found workaround to make it work, take look at this answer https://github.com/apollographql/subscriptions-transport-ws/issues/333#issuecomment-359261024
the reason was due to server-side rendering; these statements must run in the browser, so we test if we have process.browser !!
relevant section from the attached github link:
const wsLink = process.browser ? new WebSocketLink({ // if you instantiate in the server, the error will be thrown
uri: `ws://localhost:4000/subscriptions`,
options: {
reconnect: true
}
}) : null;
const httplink = new HttpLink({
uri: 'http://localhost:3000/graphql',
credentials: 'same-origin'
});
const link = process.browser ? split( //only create the split in the browser
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsLink,
httplink,
) : httplink;
This answer seems to be more actual
https://github.com/apollographql/subscriptions-transport-ws/issues/333#issuecomment-775578327
You should install ws by npm i ws and add webSocketImpl: ws to WebSocketLink argument.
import ws from 'ws';
const wsLink = new WebSocketLink({
uri: endpoints.ws,
options: {
reconnect: true,
connectionParams: () => ({
...getToken() && {Authorization: getToken()}
})
},
webSocketImpl: ws
});
Solution: Make wsLink a function variable like the code below.
// src/apollo.ts
import { ApolloClient, HttpLink, InMemoryCache } from "#apollo/client";
import { GraphQLWsLink } from "#apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
const httpLink = new HttpLink({
uri: 'http://localhost:3000/graphql'
});
const wsLink = () => {
return new GraphQLWsLink(createClient({
url: 'ws://localhost:3000/graphql'
}));
}
export const apolloClient = new ApolloClient({
link: typeof window === 'undefined' ? httpLink : wsLink(),
cache: new InMemoryCache(),
});
// pages/_app.tsx
import { ApolloProvider } from "#apollo/client";
import { apolloClient } from "../src/apollo";
function MyApp({ Component, pageProps }) {
return (
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
);
}
I am new to NextJS. I have a page that needs to display real-time data pulled from a Hasura GraphQL backend.
In other non-NextJS apps, I have used GraphQL subscriptions with the Apollo client library. Under the hood, this uses websockets.
I can get GraphQL working in NextJS when it's not using subscriptions. I'm pretty sure this is running on the server-side:
import React from "react";
import { AppProps } from "next/app";
import withApollo from 'next-with-apollo';
import { ApolloProvider } from '#apollo/react-hooks';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { getToken } from "../util/auth";
interface Props extends AppProps {
apollo: any
}
const App: React.FC<Props> = ({ Component, pageProps, apollo }) => (
<ApolloProvider client={apollo}>
<Component {...pageProps}/>
</ApolloProvider>
);
export default withApollo(({ initialState }) => new ApolloClient({
uri: "https://my_hasura_instance.com/v1/graphql",
cache: new InMemoryCache().restore(initialState || {}),
request: (operation: any) => {
const token = getToken();
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : ''
}
});
}
}))(App);
And I use it this way:
import { useQuery } from '#apollo/react-hooks';
import { gql } from 'apollo-boost';
const myQuery = gql`
query {
...
}
`;
const MyComponent: React.FC = () => {
const { data } = useQuery(myQuery);
return <p>{JSON.stringify(data)}</p>
}
However, I would instead like to do this:
import { useSubscription } from '#apollo/react-hooks';
import { gql } from 'apollo-boost';
const myQuery = gql`
subscription {
...
}
`;
const MyComponent: React.FC = () => {
const { data } = useSubscription(myQuery);
return <p>{JSON.stringify(data)}</p>
}
What I've tried
I've tried splitting the HttpLink and WebsocketLink elements in the ApolloClient, like so:
import React from "react";
import { AppProps } from "next/app";
import { ApolloProvider } from '#apollo/react-hooks';
import withApollo from 'next-with-apollo';
import { InMemoryCache } from "apollo-cache-inmemory";
import ApolloClient from "apollo-client";
import { split } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';
import { getToken } from "../util/auth";
interface Props extends AppProps {
apollo: any
}
const App: React.FC<Props> = ({ Component, pageProps, apollo }) => (
<ApolloProvider client={apollo}>
<Component {...pageProps}/>
</ApolloProvider>
);
const wsLink = new WebSocketLink({
uri: "wss://my_hasura_instance.com/v1/graphql",
options: {
reconnect: true,
timeout: 10000,
connectionParams: () => ({
headers: {
authorization: getToken() ? `Bearer ${getToken()}` : ""
}
})
},
});
const httpLink = new HttpLink({
uri: "https://hasura-g3uc.onrender.com/v1/graphql",
});
const link = process.browser ? split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink
) : httpLink;
export default withApollo(({ initialState }) => new ApolloClient({
link: link,
cache: new InMemoryCache().restore(initialState || {}),
}))(App);
But when I load the page, I get an Internal Server Error, and this error in the terminal:
Error: Unable to find native implementation, or alternative implementation for WebSocket!
It seems to me that the ApolloClient is then being generated on the server-side, where there is no WebSocket implementation. How can I make this happen on the client-side?
Found workaround to make it work, take look at this answer https://github.com/apollographql/subscriptions-transport-ws/issues/333#issuecomment-359261024
the reason was due to server-side rendering; these statements must run in the browser, so we test if we have process.browser !!
relevant section from the attached github link:
const wsLink = process.browser ? new WebSocketLink({ // if you instantiate in the server, the error will be thrown
uri: `ws://localhost:4000/subscriptions`,
options: {
reconnect: true
}
}) : null;
const httplink = new HttpLink({
uri: 'http://localhost:3000/graphql',
credentials: 'same-origin'
});
const link = process.browser ? split( //only create the split in the browser
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsLink,
httplink,
) : httplink;
This answer seems to be more actual
https://github.com/apollographql/subscriptions-transport-ws/issues/333#issuecomment-775578327
You should install ws by npm i ws and add webSocketImpl: ws to WebSocketLink argument.
import ws from 'ws';
const wsLink = new WebSocketLink({
uri: endpoints.ws,
options: {
reconnect: true,
connectionParams: () => ({
...getToken() && {Authorization: getToken()}
})
},
webSocketImpl: ws
});
Solution: Make wsLink a function variable like the code below.
// src/apollo.ts
import { ApolloClient, HttpLink, InMemoryCache } from "#apollo/client";
import { GraphQLWsLink } from "#apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
const httpLink = new HttpLink({
uri: 'http://localhost:3000/graphql'
});
const wsLink = () => {
return new GraphQLWsLink(createClient({
url: 'ws://localhost:3000/graphql'
}));
}
export const apolloClient = new ApolloClient({
link: typeof window === 'undefined' ? httpLink : wsLink(),
cache: new InMemoryCache(),
});
// pages/_app.tsx
import { ApolloProvider } from "#apollo/client";
import { apolloClient } from "../src/apollo";
function MyApp({ Component, pageProps }) {
return (
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
);
}
I have a reactjs application with nestjs + graphql + subscription server.
I have successfully setup graphql+subscriptions on the server. I can test it through the interactive playground interface. Everything works fine on server side.
Now I have been trying to setup graphql subscription on the client with no success. I have looked at countless tutorials and similar (or even same) github issues. Here is my client setup.
I don't know what I am doing wrong:
import React from 'react';
import { ApolloProvider } from '#apollo/react-hooks';
import { ApolloClient } from 'apollo-client';
import { getMainDefinition } from 'apollo-utilities';
import { split } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { IntrospectionFragmentMatcher, InMemoryCache } from 'apollo-cache-inmemory';
// this is a factory function I'm using to create a wrapper for the whole application
const ApolloProviderFactory = (props) => {
const { graphQlUrl, introspectData } = props;
const httpLink = new HttpLink({
uri:`http://${graphQlUrl}`,
});
const wsLink = new WebSocketLink({
uri: `ws://${graphQlUrl}`,
options: {
reconnect: true,
},
});
const link = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition'
&& definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: introspectData,
});
const cache = new InMemoryCache({ fragmentMatcher });
const client = new ApolloClient({
link,
cache,
});
// this component will wrap the whole application
const ApolloWrapper = ({ children }: ApolloWrapperProps) => (
<ApolloProvider client={client}>{children}</ApolloProvider>
);
return ApolloWrapper;
}
Here is the error I'm getting when I run the app:
Any help would be greatly appreciated.
I had the pace.js library which was somehow interfering with the whole socket thing. After I disabled it, every thing works as expected.
I'm using react on Apollo GraphQL subscriptions and I can receive updates on Apollo Playground but not on Client. Here is the response on the Apollo Playground:
Graphql Server is on http://localhost:4000/ and subscriptions on ws://localhost:4000/graphql. However, it works on the playground but not on client-side. I have set up Apollo client in this manner to receive updates from server:
import ApolloClient from 'apollo-boost';
import { WebSocketLink } from 'apollo-link-ws';
import { HttpLink } from 'apollo-link-http';
import { split } from 'apollo-link';
import { getMainDefinition } from 'apollo-utilities';
const httpLink = new HttpLink({
uri: 'http://localhost:4000/graphql'
});
export const wsLink = new WebSocketLink({
uri: `ws://localhost:4000/graphql`,
options: {
reconnect: false
}
});
export const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
export const client = new ApolloClient({
uri: 'http://localhost:4000/',
});
In my view I have used useSubscriptions:
const MESSAGE_SENT_SUBSCRIPTION = gql`subscription {
messageSent {
id
message
}
}`
const {data: newMessage, loading: newMessageLoading} = useSubscription(MESSAGE_SENT_SUBSCRIPTION, {});
And on render, I have used:
{!newMessageLoading && JSON.stringify(newMessage)}
But from client, it doesn't receive updates but I am sure that it connects with Graphql WebSockets server.
Server Side:
let database = require("./src/database.js")
let schema = require("./src/schema.js");
let resolvers = require("./src/resolvers.js");
let {ApolloServer} = require("apollo-server");
// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({
typeDefs: schema,
resolvers: resolvers,
context: {
database
}
});
// The `listen` method launches a web server.
server.listen().then(({ url,subscriptionsUrl ,subscriptionsPath}) => {
console.log(`🚀 Server ready at ${url}`);
console.log(`realtime here at ${subscriptionsUrl} and path ${subscriptionsPath}`)
});
What I'm doing wrong here, Is there anyone who came across with such issue?
You need to pass splited link to ApolloClient constructor.
Try to pass it like this (client side):
import ApolloClient from 'apollo-boost';
import { WebSocketLink } from 'apollo-link-ws';
import { HttpLink } from 'apollo-link-http';
import { split } from 'apollo-link';
import { onError } from 'apollo-link-error';
import { getMainDefinition } from 'apollo-utilities';
const httpLink = new HttpLink({
uri: 'http://localhost:4000/graphql'
});
export const wsLink = new WebSocketLink({
uri: `ws://localhost:4000/subscriptions`,
options: {
reconnect: false
}
});
export const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
export const graphqlServer = new ApolloClient({
link: ApolloLink.from([
onError(({
graphQLErrors,
networkError
}) => {
if (graphQLErrors) {
graphQLErrors.map(({
message,
locations,
path
}) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
}
if (networkError) {
console.log(`[Network error]: ${networkError}`);
}
}),
link // YOUR LINK (NOW MATCHING YOUR CODE)
])
});
And server side:
...
const server = new ApolloServer({
typeDefs: schema,
resolvers: resolvers,
subscriptions: {
path: '/subscriptions'
},
context: {
database
}
});
...
Note that /subscriptions also passed to ApolloClient
I had to import ApolloClient from apollo-client. Here is the working configuration for client-side:
import ApolloClient from 'apollo-client';
import { WebSocketLink } from 'apollo-link-ws';
import { HttpLink } from 'apollo-link-http';
import { split } from 'apollo-link';
import { onError } from 'apollo-link-error';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { getMainDefinition } from 'apollo-utilities';
export const httpLink = new HttpLink({
uri: "http://localhost:4000/graphql", // use https for secure endpoint
});
// Create a WebSocket link:
export const wsLink = new WebSocketLink({
uri: "ws://localhost:4000/subscriptions", // use wss for a secure endpoint
options: {
reconnect: true
}
});
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
export const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsLink,
httpLink,
);
// Instantiate client
export const client = new ApolloClient({
link,
uri: "http://localhost:4000/graphql",
cache: new InMemoryCache()
})
I'm trying to solve how handle throwed apollo-server mutation error on apollo client side.
This is my simplified implementation of mutation (createCustomer):
Mutation: {
createCustomer: async (_, { photoFile, customer }) => {
const rootPath = path.resolve("./public");
const customerPath = path.join(rootPath, "/photos/customers");
try {
const {
dataValues: { customerID, firstname, lastname, email, phone }
} = await models.Customer.create(customer);
const customerUniqueDir = path.join(customerPath,
`${customerID}`);
} catch (createCustomerError) {
// throw new apollo-server error
throw new UserInputError();
}
}
}
on client side I get following error:
(first not red error is just console.log in catch block on client)
This error is thrown by apollo-link:
here is the response from server:
Here is the implementation of apollo-client:
import { ApolloClient } from "apollo-client";
import { ApolloLink } from "apollo-link";
import { ErrorLink } from "apollo-link-error";
import { withClientState } from "apollo-link-state";
import { createUploadLink } from "apollo-upload-client";
import { ApolloProvider } from "react-apollo";
import { InMemoryCache } from "apollo-cache-inmemory";
import App from "./App";
const cache = new InMemoryCache({
addTypename: false
});
const stateLink = withClientState({
cache,
resolvers: {
Mutation: {}
},
defaults: {
customers: { customers: [], count: 0 }
}
});
const uploadLink = createUploadLink({ uri: "http://localhost:8000/graphql" });
const errorLink = new ErrorLink();
const client = new ApolloClient({
link: ApolloLink.from([stateLink, errorLink, uploadLink]),
cache,
connectToDevTools: true
});
ReactDOM.render(
<BrowserRouter>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</BrowserRouter>,
document.getElementById("root")
);
Is there any solution how could I handle mutation error on client ?
Thanks for answer
Solution:
The error appeared in apollo-link. So I looked into my implementation of graphql-client and I realized that I forgot to use apollo-link-http module.
So I added following lines of code:
import { HttpLink } from "apollo-link-http";
const httpLink = new HttpLink({ uri: "http://localhost:8000/graphql" });
const client = new ApolloClient({
link: ApolloLink.from([stateLink,errorLink, httpLink, uploadLink]),
cache,
connectToDevTools: true
});