NodeJS 无法使用graphql-ws订阅获取初始数据

cuxqih21  于 2022-11-04  发布在  Node.js
关注(0)|答案(1)|浏览(230)

我对使用graphql-ws和graphql-yoga服务器还很陌生,所以如果这是一个天真的问题或我的错误,请原谅我。
我看过graphql-ws文档,它把模式写成了参数,不幸的是,文档中使用的模式定义缺少一个引用。

  • 在添加一个新的待办事项(使用addTodo)后,它会显示两个待办事项。* 因此,我相信无论何时在Yoga Graphiql资源管理器上运行订阅,它都无法返回初始待办事项列表。

它应该在模式定义中订阅和发布初始待办事项后立即显示。我的理解是,在模式定义中缺少了一些东西,当尝试访问 Yoga Graphiql explorer 时,没有显示待办事项列表。
有没有人有过类似的经历,并能够解决它?我错过了什么?

使用的库

后端

  • 图形瑜伽
  • 工作站
  • 图形-ws
    前端
  • 实心-js
  • 旺卡
    待办事项-已在架构中声明
{
  id: "1",
  title: "Learn GraphQL + Solidjs",
  completed: false
}

截图

代码段

结构描述定义

import { createPubSub } from 'graphql-yoga';
import { Todo } from "./types";

let todos = [
    {
        id: "1",
        title: "Learn GraphQL + Solidjs",
        completed: false
    }
];

// channel
const TODOS_CHANNEL = "TODOS_CHANNEL";

// pubsub
const pubSub = createPubSub();

const publishToChannel = (data: any) => pubSub.publish(TODOS_CHANNEL, data);

// Type def
const typeDefs = [`
    type Todo {
        id: ID!
        title: String!
        completed: Boolean!
    }

    type Query {
        getTodos: [Todo]!
    }

    type Mutation {
        addTodo(title: String!): Todo!
    }

    type Subscription {
        todos: [Todo!]
    }
`];

// Resolvers
const resolvers = {
    Query: {
        getTodos: () => todos
    },
    Mutation: {
        addTodo: (_: unknown, { title }: Todo) => {
            const newTodo = {
                id: "" + (todos.length + 1),
                title,
                completed: false
            };
            todos.push(newTodo);
            publishToChannel({ todos });
            return newTodo;
        },
    Subscription: {
        todos: {
            subscribe: () => {
                const res = pubSub.subscribe(TODOS_CHANNEL);
                publishToChannel({ todos });
                return res;
            }
        },
    },
};

export const schema = {
    resolvers,
    typeDefs
};

服务器后端

import { createServer } from "graphql-yoga";
import { WebSocketServer } from "ws";
import { useServer } from "graphql-ws/lib/use/ws";

import { schema } from "./src/schema";
import { execute, ExecutionArgs, subscribe } from "graphql";

async function main() {
    const yogaApp = createServer({
        schema,
        graphiql: {
            subscriptionsProtocol: 'WS', // use WebSockets instead of SSE
        },
    });

    const server = await yogaApp.start();
    const wsServer = new WebSocketServer({
        server,
        path: yogaApp.getAddressInfo().endpoint
    });

    type EnvelopedExecutionArgs = ExecutionArgs & {
        rootValue: {
            execute: typeof execute;
            subscribe: typeof subscribe;
        };
    };

    useServer(
        {
            execute: (args: any) => (args as EnvelopedExecutionArgs).rootValue.execute(args),
            subscribe: (args: any) => (args as EnvelopedExecutionArgs).rootValue.subscribe(args),
            onSubscribe: async (ctx, msg) => {
                const { schema, execute, subscribe, contextFactory, parse, validate } =
                    yogaApp.getEnveloped(ctx);

                const args: EnvelopedExecutionArgs = {
                    schema,
                    operationName: msg.payload.operationName,
                    document: parse(msg.payload.query),
                    variableValues: msg.payload.variables,
                    contextValue: await contextFactory(),
                    rootValue: {
                        execute,
                        subscribe,
                    },
                };

                const errors = validate(args.schema, args.document);
                if (errors.length) return errors;
                return args;
            },
        },
        wsServer,
    );

}

main().catch((e) => {
    console.error(e);
    process.exit(1);
});
zzwlnbp8

zzwlnbp81#

应用这些更改

Mutation: {
    addTodo: (_: unknown, { title }: Todo) => {
        const newTodo = {
            id: "" + (todos.length + 1),
            title,
            completed: false
        };
        todos.push(newTodo);
        publishToChannel({ todos });
        return newTodo;
    },
Subscription: {
    todos: {
        subscribe: () => {
            return Repeater.merge(
               [
                   new Repeater(async (push, stop) => {
            push({ todos });
            await stop;
        }),
                   pubSub.subscribe(TODOS_CHANNEL),
               ]
            )
        }
    },
},

首先,npm i @中继器js/中继器,然后导入中继器

相关问题