I have subscriptions working fine by themselves in a Chat service at: http://localhost:3002/graphql, ws://localhost:3002/subscriptions.
I am trying to build a Gateway server so Gateway => Chat Service (and many other microservices).
_(By the way, is this schema stitching Gateway stuff supposed to go in the Server or the Client? Right now I have in its own Node.js server.)_
import { makeRemoteExecutableSchema, introspectSchema, mergeSchemas } from 'graphql-tools';
import fetch from 'node-fetch';
import { HttpLink } from 'apollo-link-http';
import { ApolloLink } from 'apollo-link';
import { setContext } from 'apollo-link-context';
import { WebSocketLink } from 'apollo-link-ws';
import ws from 'ws';
async function makeSchema() {
const ContextLink = setContext((request, previousContext) => ({
headers: {
authorization: previousContext.graphqlContext.headers.authorization,
},
}));
const AuthLink = new HttpLink({
uri: 'http://localhost:3001/graphql',
fetch,
});
const AuthSchema = makeRemoteExecutableSchema({
schema: await introspectSchema(AuthLink),
link: ApolloLink.from([ContextLink, AuthLink]),
});
const ChatLink = new HttpLink({
uri: 'http://localhost:3002/graphql',
fetch,
});
const SubscriptionLink = new WebSocketLink({
uri: 'ws://localhost:3002/subscriptions',
options: {
reconnect: true,
},
webSocketImpl: ws,
});
const ChatSchema = makeRemoteExecutableSchema({
schema: await introspectSchema(ChatLink),
link: SubscriptionLink, // SubscriptionLink is terminating, so no ChatLink here?
});
const mergedSchema = mergeSchemas({
schemas: [AuthSchema, ChatSchema],
});
return mergedSchema;
}
export const schema = makeSchema();
After setting link: SubscriptionLink, queries/mutations/subscriptions to localhost:3002 fail because context is lost and becomes {}. The queries/mutations worked when link: ChatLink, and the subscriptions only work when I hit ws://localhost:3002/subscriptions directly without stitching/links.
What am I doing wrong?
EDIT: Also tried this and no luck:
const ChatLink = ApolloLink.split(
({ query: { definitions } }) => definitions.some(({ kind, operation }) => kind === 'OperationDefinition' && operation === 'subscription'),
new WebSocketLink({
uri: `ws://localhost:3002/subscriptions`,
options: {
reconnect: true,
},
webSocketImpl: ws,
}),
new HttpLink({
uri: 'http://localhost:3002/graphql',
fetch,
})
);
const ChatSchema = makeRemoteExecutableSchema({
schema: await introspectSchema(ChatLink),
link: ChatLink,
});
Hi @booboothefool,
You should look into from and split from apollo-link to create your link. Maybe the sample bellow will help you figure this out :
import { from, split } from 'apollo-link';
import { setContext } from 'apollo-link-context';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';
import { importSchema } from 'graphql-import';
import { makeRemoteExecutableSchema } from 'graphql-tools';
import fetch from 'node-fetch';
import path from 'path';
import WebSocket from 'ws';
export default async (httpUri, wsUri, filename) => {
// 1. Create Apollo Link that's connected to the underlying GraphQL API
const httpLink = new HttpLink({ uri: httpUri, fetch });
// Auth link
const httpAuthLink = setContext((request, previousContext) => ({
headers: {
authorization: previousContext.graphqlContext.headers.authorization,
},
}));
// WebSocket link
const wsLink = new WebSocketLink({
uri: wsUri,
options: {
reconnect: true,
},
webSocketImpl: WebSocket,
});
const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsLink,
from([
httpAuthLink,
httpLink,
]),
);
// 2. Retrieve schema definition of the underlying GraphQL API
const rootPath = path.join.bind(this, __dirname, './');
// Works with introspectSchema but be careful of performances issues
const schema = importSchema(rootPath(`./schemas/${filename}`));
// 3. Create the executable schema based on schema definition and Apollo Fetch
const databaseServiceExecutableSchema = makeRemoteExecutableSchema({
schema,
link,
});
return databaseServiceExecutableSchema;
};
Remote schemas stitching with subscriptions is a little tricky but very powerful.
Most helpful comment
Hi @booboothefool,
You should look into
fromandsplitfromapollo-linkto create yourlink. Maybe the sample bellow will help you figure this out :Remote schemas stitching with subscriptions is a little tricky but very powerful.