使用 graphql 和 apollo 引发描述性错误

Posted

技术标签:

【中文标题】使用 graphql 和 apollo 引发描述性错误【英文标题】:throw a descriptive error with graphql and apollo 【发布时间】:2020-10-14 10:33:31 【问题描述】:

考虑以下类:

// entity/Account.ts
import  Entity, PrimaryGeneratedColumn, Column, BaseEntity, Index, CreateDateColumn, UpdateDateColumn  from 'typeorm'
import  Field, Int, ObjectType  from 'type-graphql'

@ObjectType()
@Entity()
export class Account extends BaseEntity 
  @Field(() => Int)
  @PrimaryGeneratedColumn()
  id: number

  @Field()
  @Column( length: 50, unique: true )
  @Index( unique: true )
  accountIdentifier: string

  @Field( nullable: true )
  @Column( length: 100 )
  name?: string

对应的解析器:

// AccountResolver.ts
@Resolver()
export class AccountResolver 
  @Mutation(() => Account)
  async addAccount(@Arg('options', () => AccountInput) options: AccountInput) 
    try 
      // if (!options.accountIdentifier) 
      //   throw new Error(`Failed adding account: the accountIdentifier is missing`)
      // 
      return await Account.create(options).save()
     catch (error) 
      if (error.message.includes('Cannot insert duplicate key')) 
        throw new Error(
          `Failed adding account: the account already exists. $error`
        )
       else 
        throw new Error(`Failed adding account: $error`)
      
    
  

Jest 测试文件

// AccountResolver.test.ts
describe('the addAccount Mutation', () => 
  it('should throw an error when the accountIdentifier is missing', async () => 
    await expect(
      client.mutate(
        mutation: gql`
        mutation 
          addAccount(
            options: 
              name: "James Bond"
              userName: "James.Bond@contoso.com"
            
          ) 
            accountIdentifier
          
        
      `,
      )
    ).rejects.toThrowError('the accountIdentifier is missing')
  )

accountIdentifier 字段是必填字段,当请求中缺少该字段时,应抛出描述性错误消息。但是,抛出的错误是:

“网络错误:响应不成功:收到状态码 400”

修改错误信息的正确方法是什么?我查看了type-graphql 和class-validators,并确保设置了validate: true,但它没有给出描述性错误。

编辑

在检查了 graphql playground 之后,默认情况下它确实显示了正确的错误消息。剩下的唯一问题是如何编写笑话测试以便它可以读取此消息:


  "error": 
    "errors": [
      
        "message": "Field AccountInput.accountIdentifier of required type String! was not provided.",

感谢您能给我的任何帮助。

【问题讨论】:

【参考方案1】:

您的客户端返回的ApolloError 包含响应中返回的errors 以及执行请求时遇到的任何网络错误。前者可在graphQLErrors 属性下访问,后者可在networkError 属性下访问。 Instea dof 使用 toThrowError,你应该使用 toMatchObject 代替:

const expectedError = 
  graphQLErrors: [ message: 'the accountIdentifier is missing' ]

await expect(client.mutate(...)).rejects.toMatchObject(expectedError)

但是,我建议避免使用 Apollo Client 进行测试。相反,您可以直接针对您的架构执行操作。

import  buildSchema  from 'type-graphql'
import  graphql  from 'graphql'

const schema = await buildSchema(
  resolvers: [...],
)
const query = ' someField '
const context = 
const variables = 
const  data, errors  = await graphql(schema, query, , context, variables)

【讨论】:

感谢您的回答,但您收到的建议开玩笑是“graphQLErrors”:Array [],而不是graphql Playground 中可见的错误消息。使用正确的错误消息对象更新了 OP。根据您的建议,我将尝试将我的代码转换为不使用 apollo-client @DarkLite1 对不起,我忘了提到这里的另一个问题是您发送的查询实际上是无效的(这就是 400 状态所表示的)。您可以检查错误对象上networkError 属性的值以确定原因。 最后一个问题:不使用apollo-client有什么好处吗?你为什么这么建议? 如果您有一个 GraphQL API,您想要测试的是来自该 API 的响应,而不一定是任何一个客户端如何使用该响应。 真的!并且直接使用graphql 也更干净。只剩下一个问题,符合我对这个错误对象的开玩笑期望` [GraphQLError: Field AccountInput.accountIdentifier of required type String!没有提供。],`。似乎无法正确使用语法。

以上是关于使用 graphql 和 apollo 引发描述性错误的主要内容,如果未能解决你的问题,请参考以下文章

所有 apollo 查询错误都会引发网络 400 错误

GraphQL 订阅引发跨源错误

Apollo GraphQL Android 无法解决“无法解析 http 响应”错误

使用 Express-GraphQL 和 React-Apollo 订阅 GraphQL

在 GraphQL 和 Apollo 中检索数组

使用 graphql 和 apollo 客户端刷新 Angular 令牌