У меня есть приложение на базе GraphQL. Части запроса и мутации работают хорошо. Я пытаюсь добавить подписку GraphQL.
Код части подписки на сервер GraphQL вдохновлен демонстрацией в файле readme apollographql/подписки-транспорт-ws.
Пожалуйста, также проверьте комментарии в коде для получения более подробной информации.
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',
},
);
Я использую Altair GraphQL-клиент для тестирования, так как он поддерживает подписку на GraphQL.
Как видно на скриншоте, он получает новые данные каждый раз, когда данные изменяются в базе данных.
Однако meChanged — это null, и он не выдает никаких ошибок. Есть идеи? Спасибо
@Престон Спасибо! Только что обновил заголовок. Я надеюсь, что смогу опубликовать сообщение об ошибке консоли Chrome, но я еще не начал создавать часть подписки для клиента, так как отсутствует документ об использовании подписки GraphQL без какой-либо структуры, такой как Apollo. Вот почему я использую клиент Altair GraphQL в качестве отправной точки, чтобы понять, как работает подписка на GraphQL.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Наконец-то появилась новая библиотека, которая может выполнять работу без полноценного фреймворка Apollo.
https://github.com/enisdenjo/graphql-ws
Вот коды, которые у меня есть:
Сервер (язык определения схемы GraphQL)
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
);
Сервер (способ объекта GraphQL.js GraphQLSchema)
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
);
Клиент
import { createClient } from 'graphql-ws';
const client = createClient({
url: 'wss://localhost:5000/graphql',
});
client.subscribe(
{
query: 'subscription { greeting }',
},
{
next: (data) => {
console.info('data', data);
},
error: (error) => {
console.error('error', error);
},
complete: () => {
console.info('no more greetings');
},
}
);
РАСКРЫТЬ: я не связан с библиотекой.
Я попробовал первый сервер, т. Е. (Сервер (язык определения схемы GraphQL)) и клиентский код, поскольку он должен выполнять один POC, но я получил следующую ошибку: - «Поле подписки должно возвращать асинхронный итеративный объект. Получено: {}.». Не могли бы вы сообщить мне, что я могу делать неправильно, так как я нуб в подписках на graphql
@ sagg1295 проверьте github.com/Hongbo-Miao/hongbomiao.com/blob/main/api/src/graphQL/…, это может вам помочь. Это полноценная рабочая демонстрация.
Спасибо за это. Я хочу прояснить одну вещь в приведенной выше ссылке, которую вы использовали модуль graphql-subscriptions. Нужно ли делать подписку, используя это? Разве мы не можем просто использовать graphql-ws, ws и graphql для выполнения подписок graphql? Поскольку я следовал коду, указанному на странице github graphql-ws. Это не сработало. Если хотите, я могу поделиться своим репозиторием на github, если вы сможете пройти через это, имея всего два файла с логикой.
@ sagg1295 способ определения языка схемы GraphQL в ответе также использует graphql-subscriptions с graphql-ws, что то же самое.
но когда я искал в Google, чтобы делать подписки в graphql, я также обнаружил, что graphql-подписки — это отдельная вещь, чем graphql-ws. Может я ошибаюсь. Я думал, что это разные подходы к выполнению подписка в graphql.
@sagg1295 графql-ws находится на том же уровне, что и подписки-транспорт-ws. А graphql-подписки - вещь другого уровня.
как обрабатывать переменные в запросе на подписку graphql, переданном клиентом на сервер, можете ли вы привести какой-либо пример? пытался просмотреть документацию, но не смог пройти через это
В вашем первом примере есть import WebSocket from 'ws';, но затем вы делаете ws.Server, что правильно?
Я не знаю, что означает всегда, и вы не включаете сообщение об ошибке с панели «Сеть» в Chrome Dev Tools, поэтому диагностика вашей проблемы затруднена. Однако вы смотрели на это: stackoverflow.com/questions/56319137/…