Angular &引用;无法为不可为空的字段返回null;使用Graphql在NestJS上订阅时
我用Angular &引用;无法为不可为空的字段返回null;使用Graphql在NestJS上订阅时,angular,graphql,apollo-client,nestjs,Angular,Graphql,Apollo Client,Nestjs,我用Nestjs完成了一个nodejs后端,我正在使用Graphql。我的前端是Ionic/Angular,使用Apollo Angular进行graphql操作。 我在订阅数据添加/更改时遇到问题。Playerd(由Nestjs提供)工作正常,这提示我问题在前端 在我的数据模型中有game和scores,每个分数都属于一个游戏。在前端,我试着聆听一个特定游戏中添加的新分数 后端 下面是我的解析器的一个片段: @Mutation(returns => Score) async addSco
Nestjs
完成了一个nodejs后端,我正在使用Graphql
。我的前端是Ionic/Angular,使用Apollo Angular进行graphql操作。
我在订阅数据添加/更改时遇到问题。Playerd(由Nestjs提供)工作正常,这提示我问题在前端
在我的数据模型中有game
和scores
,每个分数都属于一个游戏。在前端,我试着聆听一个特定游戏中添加的新分数
后端
下面是我的解析器的一个片段:
@Mutation(returns => Score)
async addScore(@Args('data') data: ScoreInput): Promise<IScore> {
return await this.scoresService.createScore(data);
}
@Subscription(returns => Score, {
filter: (payload, variables) => payload.scoreAdded.game + '' === variables.gameId + '',
})
scoreAdded(@Args('gameId') gameId: string) {
return this.pubSub.asyncIterator('scoreAdded');
}
这些在my schema.gql中:
type Score {
id: String
game: String
result: Int
}
type Subscription {
scoreAdded(gameId: String!): Score!
}
前端
根据阿波罗angular的文档,在我的前端,我有这样的服务:
import { Injectable } from '@angular/core';
import { Subscription } from 'apollo-angular';
import { SCORE_ADDED } from './graphql.queries';
@Injectable({
providedIn: 'root',
})
export class ScoreListenerService extends Subscription {
document = SCORE_ADDED;
}
这在前端的graphql.querys中:
export const SCORE_ADDED = gql`
subscription scoreAdded($gameId: String!) {
scoreAdded(gameId: $gameId) {
id
game
result
}
}
`;
我在我的组件中使用的服务如下:
this.scoreListener.subscribe({ gameId: this.gameId }).subscribe(({ data }) => {
const score = data.scoreAdded;
console.log(score);
});
问题
所有这些,我的前端给了我一个错误错误:GraphQL错误:对于不可为null的字段订阅,无法返回null。scoreAdded。
在操场上这样做订阅是有效的,一点问题也没有
subscription {
scoreAdded(gameId: "5d24ad2c4cf6d3151ad31e3d") {
id
game
result
}
}
不同的问题
我注意到,如果我在后端的解析器中使用resolve
,如下所示:
@Subscription(returns => Score, {
resolve: value => value,
filter: (payload, variables) => payload.scoreAdded.game + '' === variables.gameId + '',
})
scoreAdded(@Args('gameId') gameId: string) {
return this.pubSub.asyncIterator('scoreAdded');
}
前端中的错误消失了,但它会将订阅中的数据搞砸,并在每个属性中获得带有null的附加分数,并且根本不会触发前端中的订阅
有什么帮助吗,我做错了什么?
在我看来,我的前端是不正确的,但我不确定这是我的错还是可能是阿波罗angular中的错误…好的,我的问题解决了。正如我所怀疑的,问题在于前端代码。因此,我在后端实现nestjs的方式没有问题。事实证明,我犯了一个愚蠢的错误,没有为订阅初始化WS,这在这里得到了清楚的解释
所以,我改变了这个
const graphqlUri = 'http://localhost:3000/graphql';
export function createApollo(httpLink: HttpLink) {
return {
link: httpLink.create({ graphqlUri }),
cache: new InMemoryCache(),
defaultOptions: {
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all',
},
},
};
}
对此
const graphqlUri = 'http://localhost:3000/graphql';
const wsUrl = 'ws://localhost:3000/graphql';
export function createApollo(httpLink: HttpLink) {
const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
new WebSocketLink({
uri: wsUrl,
options: {
reconnect: true,
},
}),
httpLink.create({
uri: graphqlUri,
})
);
return {
link,
cache: new InMemoryCache(),
defaultOptions: {
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all',
},
},
};
}
上面提供的答案是正确的,但对于希望查看所使用的软件包版本和导入的文件的用户,请检查此解决方案:
package.json依赖项
{
"dependencies": {
"@apollo/client": "^3.2.5",
"@apollo/link-ws": "^2.0.0-beta.3",
"apollo-angular": "^2.0.4",
"subscriptions-transport-ws": "^0.9.18",
}
}
图形ql.module.ts代码
import { WebSocketLink } from '@apollo/link-ws';
import { NgModule } from '@angular/core';
import { APOLLO_OPTIONS } from 'apollo-angular';
import { InMemoryCache, split } from '@apollo/client/core';
import { getMainDefinition } from '@apollo/client/utilities';
import { HttpLink } from 'apollo-angular/http';
const uri = 'http://localhost:3000/graphql';
const wsUrl = 'http://localhost:3000/graphql';
export function createApollo(hLink: HttpLink) {
const ws = new WebSocketLink({
uri: wsUrl,
options: {
reconnect: true
}
});
const http = hLink.create({uri});
const newLink = split(
({ query }) => {
const def = getMainDefinition(query);
return def.kind === 'OperationDefinition' && def.operation === 'subscription';
},
ws,
http
);
return {
link: newLink,
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
fetchPolicy: 'network-only',
errorPolicy: 'all'
}
}
};
}
@NgModule({
providers: [
{
provide: APOLLO_OPTIONS,
useFactory: createApollo,
deps: [HttpLink],
},
],
})
export class GraphQLModule {}
服务方法中是否定义了score
(即创建是否实际返回创建的模型)?是的,服务方法正确返回实际保存的模型(在所有这些情况下)。如果不在后端订阅部分定义任何resolve
,那么在Playerd上一切都可以正常工作,但是前端Apollo客户端会收到错误:GraphQL错误:无法为不可为null的字段订阅返回null。scoreAdded。
从何处导入getMainDefinition?
import { WebSocketLink } from '@apollo/link-ws';
import { NgModule } from '@angular/core';
import { APOLLO_OPTIONS } from 'apollo-angular';
import { InMemoryCache, split } from '@apollo/client/core';
import { getMainDefinition } from '@apollo/client/utilities';
import { HttpLink } from 'apollo-angular/http';
const uri = 'http://localhost:3000/graphql';
const wsUrl = 'http://localhost:3000/graphql';
export function createApollo(hLink: HttpLink) {
const ws = new WebSocketLink({
uri: wsUrl,
options: {
reconnect: true
}
});
const http = hLink.create({uri});
const newLink = split(
({ query }) => {
const def = getMainDefinition(query);
return def.kind === 'OperationDefinition' && def.operation === 'subscription';
},
ws,
http
);
return {
link: newLink,
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
fetchPolicy: 'network-only',
errorPolicy: 'all'
}
}
};
}
@NgModule({
providers: [
{
provide: APOLLO_OPTIONS,
useFactory: createApollo,
deps: [HttpLink],
},
],
})
export class GraphQLModule {}