NestJS GraphQL Subscription返回null 报非空字段不可为null错误
NestJS GraphQL Subscription 报错
Cannot return null for non-nullable field Subscription 排查与修复 问题场景
使用NestJS + GraphQL开发项目,测试Subscription基础功能时触发报错:Cannot return null for non-nullable field Subscription.orderSubscription
复现信息
- 业务层基础订阅发布测试代码:
//* ~~~~~~~~~~~~~~~~~~~ Subscription ~~~~~~~~~~~~~~~~~~~ */ @Mutation((returns) => Boolean) testSubscription() { pubsub.publish('somethingOnTrack', { somethingOnTrack: 'something', }); return true; } @Subscription((returns) => String) orderSubscription() { return pubsub.asyncIterator('somethingOnTrack'); }
- GraphQL模块配置(同时启用两种WebSocket订阅实现):
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, autoSchemaFile: true, subscriptions: { 'graphql-ws': true, 'subscriptions-transport-ws': true, }, }),
测试操作流程:
- 先在GraphQL Playground发起订阅请求:
subscription { orderSubscription }- 再触发对应mutation:
mutation { testSubscription }实际运行结果:
- Mutation正常返回预期结果:
{ "data": { "testSubscription": true } }- Subscription端返回错误:
{ "errors": [ { "message": "Cannot return null for non-nullable field Subscription.orderSubscription.", "locations": [ { "line": 2, "column": 3 } ], "path": [ "orderSubscription" ] } ], "data": null }
错误原因
NestJS GraphQL的Subscription默认解析逻辑为:从pubsub推送的payload对象中,读取与订阅方法同名的顶层字段作为返回值。
上述代码中订阅方法名为orderSubscription,但pubsub.publish推送的payload顶层只有somethingOnTrack字段,没有匹配的orderSubscription字段,解析得到的值为undefined。而自动生成的Schema中该字段为非空String类型,因此触发"非空字段返回null"的校验错误。
修复方案
两种方案二选一即可:
- 统一publish的payload字段名与订阅方法名
修改mutation中publish的payload,将顶层key改为和订阅方法一致:
@Mutation((returns) => Boolean) testSubscription() { pubsub.publish('somethingOnTrack', { // 字段名和@Subscription装饰的方法名保持一致 orderSubscription: 'something', }); return true; }
- 自定义Subscription的resolve逻辑,手动指定返回值
给@Subscription装饰器传入resolve配置,手动从payload中取出需要返回的字段,无需修改publish逻辑:
@Subscription((returns) => String, { resolve: (payload) => payload.somethingOnTrack }) orderSubscription() { return pubsub.asyncIterator('somethingOnTrack'); }
补充说明:同时启用
graphql-ws和subscriptions-transport-ws不会直接导致该错误,但生产环境建议根据客户端使用的协议只保留对应实现,避免不必要的连接冲突。
内容的提问来源于stack exchange,提问作者Yue Dong
相关产品推荐
相关产品推荐

