I have a GraphQL powered app. The query and mutation parts work well. I try to add GraphQL subscription.
The server GraphQL subscription part code is inspired by the demo in the readme of apollographql/subscriptions-transport-ws.
Please also check the ments in the code for more details.
import Koa from 'koa';
import Router from 'koa-router';
import graphqlHTTP from 'koa-graphql';
import asyncify from 'callback-to-async-iterator';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import firebase from 'firebase-admin';
import { execute, subscribe } from 'graphql';
import { GraphQLObjectType, GraphQLString } from 'graphql';
const MeType = new GraphQLObjectType({
name: 'Me',
fields: () => ({
name: { type: GraphQLString },
// ...
}),
});
const listenMe = async (callback) => {
// Below the firebase API returns real-time data
return firebase
.database()
.ref('/users/123')
.on('value', (snapshot) => {
// snapshot.val() returns an Object including name field.
// Here I tested is correct, it always returns { name: 'Rose', ... }
// when some other fields inside got updated in database.
return callback(snapshot.val());
});
};
const Subscription = new GraphQLObjectType({
name: 'Subscription',
fields: () => ({
meChanged: {
type: MeType,
subscribe: () => asyncify(listenMe),
},
}),
});
const schema = new GraphQLSchema({
query: Query,
mutation: Mutation,
subscription: Subscription,
});
const app = new Koa();
app
.use(new Router()
.post('/graphql', async (ctx) => {
// ...
await graphqlHTTP({
schema,
graphiql: true,
})(ctx);
})
.routes());
const server = app.listen(3009);
SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{
server,
path: '/subscriptions',
},
);
I am using Altair GraphQL Client to test since it supports GraphQL subscription.
As the screenshot shows, it does get new data every time when the data changes in database.
However, meChanged
is null
and it does not throw any error. Any idea? Thanks
I have a GraphQL powered app. The query and mutation parts work well. I try to add GraphQL subscription.
The server GraphQL subscription part code is inspired by the demo in the readme of apollographql/subscriptions-transport-ws.
Please also check the ments in the code for more details.
import Koa from 'koa';
import Router from 'koa-router';
import graphqlHTTP from 'koa-graphql';
import asyncify from 'callback-to-async-iterator';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import firebase from 'firebase-admin';
import { execute, subscribe } from 'graphql';
import { GraphQLObjectType, GraphQLString } from 'graphql';
const MeType = new GraphQLObjectType({
name: 'Me',
fields: () => ({
name: { type: GraphQLString },
// ...
}),
});
const listenMe = async (callback) => {
// Below the firebase API returns real-time data
return firebase
.database()
.ref('/users/123')
.on('value', (snapshot) => {
// snapshot.val() returns an Object including name field.
// Here I tested is correct, it always returns { name: 'Rose', ... }
// when some other fields inside got updated in database.
return callback(snapshot.val());
});
};
const Subscription = new GraphQLObjectType({
name: 'Subscription',
fields: () => ({
meChanged: {
type: MeType,
subscribe: () => asyncify(listenMe),
},
}),
});
const schema = new GraphQLSchema({
query: Query,
mutation: Mutation,
subscription: Subscription,
});
const app = new Koa();
app
.use(new Router()
.post('/graphql', async (ctx) => {
// ...
await graphqlHTTP({
schema,
graphiql: true,
})(ctx);
})
.routes());
const server = app.listen(3009);
SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{
server,
path: '/subscriptions',
},
);
I am using Altair GraphQL Client to test since it supports GraphQL subscription.
As the screenshot shows, it does get new data every time when the data changes in database.
However, meChanged
is null
and it does not throw any error. Any idea? Thanks
- I don't know what alway means and you don't include the error message from the Network panel in Chrome Dev Tools so diagnosing your problem is difficult. However, have you looked at this: stackoverflow./questions/56319137/… – Preston Commented Jul 19, 2019 at 1:43
- @Preston Thanks! Just updated the title. I hope I could post Chrome console error message, but I haven’t started to build subscription part for client yet, since it is lack of document of using GraphQL subscription without any framework like Apollo. That is why I use Altair GraphQL Client as a start point to help me understand how GraphQL subscription works. – Hongbo Miao Commented Jul 19, 2019 at 2:07
1 Answer
Reset to default 5Finally have a new library can do the work without full Apollo framework.
https://github./enisdenjo/graphql-ws
Here are the codes that I have succeed:
Server (GraphQL Schema Definition Language)
import { useServer } from 'graphql-ws/lib/use/ws';
import WebSocket from 'ws';
import { buildSchema } from 'graphql';
const schema = buildSchema(`
type Subscription {
greeting: String
}
`);
const roots = {
subscription: {
greeting: async function* sayHiIn5Languages() {
for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) {
yield { greeting: hi };
}
},
},
};
const wsServer = new ws.Server({
server, // Your HTTP server
path: '/graphql',
});
useServer(
{
schema,
execute,
subscribe,
roots,
},
wsServer
);
Server (GraphQL.js GraphQLSchema object way)
import { execute, subscribe, GraphQLObjectType, GraphQLSchema, GraphQLString } from 'graphql';
import { useServer } from 'graphql-ws/lib/use/ws';
import WebSocket from 'ws';
import { PubSub } from 'graphql-subscriptions';
const pubsub = new PubSub();
const subscription = new GraphQLObjectType({
name: 'Subscription',
fields: {
greeting: {
type: GraphQLString,
resolve: (source) => {
if (source instanceof Error) {
throw source;
}
return source.greeting;
},
subscribe: () => {
return pubsub.asyncIterator('greeting');
},
},
},
});
const schema = new GraphQLSchema({
query,
mutation,
subscription,
});
setInterval(() => {
pubsub.publish('greeting', {
greeting: 'Bonjour',
});
}, 1000);
const wsServer = new ws.Server({
server, // Your HTTP server
path: '/graphql',
});
useServer(
{
schema,
execute,
subscribe,
roots,
},
wsServer
);
Client
import { createClient } from 'graphql-ws';
const client = createClient({
url: 'wss://localhost:5000/graphql',
});
client.subscribe(
{
query: 'subscription { greeting }',
},
{
next: (data) => {
console.log('data', data);
},
error: (error) => {
console.error('error', error);
},
plete: () => {
console.log('no more greetings');
},
}
);
DISCLOSE: I am not associated with the library.