How to throw multiple errors with express-graphql?

萝らか妹 提交于 2020-06-23 02:56:24

问题


In an express-graphql app, I have a userLogin resolver like so:

const userLogin = async ({ id, password }), context, info) => {

    if (!id) {
      throw new Error('No id provided.')
    }

    if (!password) {
      throw new Error('No password provided.')
    }

    // actual resolver logic here
    // … 
}

If the user doesn't provide an id AND a password, it will throw only one error.

{
  "errors": [
    {
      "message": "No id provided.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "userLogin"
      ]
    }
  ],
  "data": {
    "userLogin": null
  }
}

How is it possible to throw multiple errors in the errors response array?


回答1:


There is no way to throw an array of errors in JavaScript or otherwise have a single resolver reject with more than one error. A GraphQL response includes an errors array and not just a single error object because the total response can include multiple errors when those errors originate from different fields. Consider this schema and resolvers:

type Query {
  a: String
  b: String
  c: String
}

const resolvers = {
  Query: {
    a: () => { throw new Error('A rejected') },
    b: () => { throw new Error('B rejected') },
    c: () => 'Still works!',
  },
}

If you query all three fields...

query { a b c }

Your data will look something like this:

{
  "errors": [
    {
      "message": "A rejected",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "a"
      ]
    },
    {
      "message": "B rejected",
      "locations": [
        {
          "line": 3,
          "column": 3
        }
      ],
      "path": [
        "b"
      ]
    }
  ],
  "data": {
    "a": null,
    "b": null,
    "c": "Still works!"
  }
}

This is because GraphQL supports partial responses. However, keep in mind that this works because the fields are nullable. If they were non-null, those errors would bubble up to the closest nullable parent field.

Here are some alternative approaches:

You can utilize formatError to change how the errors returned by GraphQL are displayed to the client. That means you can include any sort of extra information with your errors, like an error code or multiple error messages. A simple example:

// The middleware
app.use('/graphql', graphqlExpress({
    schema: schema,
    formatError: (error) => ({
      message: error.message,
      path: error.path,
      locations: error.locations,
      errors: error.originalError.details
    })
}))

// The error class
class CustomError extends Error {
  constructor(detailsArray) {
    this.message = String(details)
    this.details = details
  }
}

// The resolver
const userLogin = async ({ id, password }), context, info) => {
    const errorDetails = []
    if (!id) errorDetails.push('No id provided.')
    if (!password) errorDetails.push('No password provided.')
    if (errorDetails.length) throw new CustomError(errorDetails)

    // actual resolver logic here
}

Your response then looks more like this:

{
  "errors": [
    {
      "message": "[No id provided.,No password provided.]",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "userLogin"
      ]
      "errors" [
        "No id provided.",
        "No password provided."
      ]
    }
  ],
  "data": {
    "userLogin": null
  }
}

That said, there's something a bit unsavory about returning user-facing error messages alongside GraphQL validation errors. Another approach that some APIs have taken is to include an errors field alongside the actual mutation response. For example:

type Mutation {
  userLogin: UserLoginResponse
}

type UserLoginResponse {
  response: User
  errors: [String!]
}

You can also use unions to achieve a similar effect:

type Mutation {
  userLogin: UserLoginResponse
}

type Errors {
  errors: [String!]!
}

union UserLoginResponse = User | Errors


来源:https://stackoverflow.com/questions/52531894/how-to-throw-multiple-errors-with-express-graphql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!