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 {}