我有一个用Nestjs
完成的nodejs后端,我正在使用Graphql
。我的前端是将Apollo-angular用于graphql的东西的Ionic / Angular。
我在订阅数据添加/更改时遇到问题。 Playground(由Nestjs提供)运行正常,这提示我问题出在前端。
我的数据模型中有game
和scores
,每个分数都属于一个游戏。在前端,我试图听听添加到特定游戏中的新分数。
这是我的resolver
的摘录:
@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');
}
这是service
方法:
async createScore(data: any): Promise<IScore> {
const score = await this.scoreModel.create(data);
this.pubSub.publish('scoreAdded', { scoreAdded: score });
}
这些在我的schema.gql中:
type Score {
id: String
game: String
result: Int
}
type Subscription {
scoreAdded(gameId: String!): Score!
}
根据Apollo-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.queries中:
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);
});
有了这些,我的前端给了我一个错误ERROR Error: GraphQL error: Cannot return null for non-nullable field Subscription.scoreAdded.
在Playground中像这样进行订阅是可行的,完全没问题。
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');
}
前端的错误消失了,但是它搞砸了订阅中的数据,操场上每个属性获得的得分都为空,前端中的订阅完全没有触发。
任何帮助,我在这里做什么错了? 在我看来,我的前端是不正确的,但是我不确定这是我的错误还是Apollo-angular中的错误...
答案 0 :(得分:0)
好,我的问题解决了。正如我所怀疑的那样,问题出在前端侧代码中。因此,我在后端侧实现nestjs的方式没有任何问题。原来对我来说这是一个愚蠢的错误,没有初始化订阅的WS,这在https://www.apollographql.com/docs/angular/features/subscriptions/中有明确说明。
所以,我改变了这个
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',
},
},
};
}
答案 1 :(得分:0)
上面提供的答案是正确的,但是对于那些想要查看所使用的软件包版本和导入的文件的人,请检查此解决方案:
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",
}
}
graphql.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 {}