Как скинуть несколько ошибок с помощью express-graphql? - PullRequest
0 голосов
/ 27 сентября 2018

В приложении express-graphql у меня есть распознаватель userLogin, например:

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
    // … 
}

Если пользователь не предоставит id И a password, он будет выбрасывать толькоодна ошибка

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

Как можно выдать несколько ошибок в массиве ответов errors?

1 Ответ

0 голосов
/ 27 сентября 2018

Нет способа выбросить массив ошибок в JavaScript или иным образом отклонить один распознаватель с более чем одной ошибкой.Ответ GraphQL включает массив errors, а не только один объект error, поскольку общий ответ может включать несколько ошибок, когда эти ошибки происходят из разных полей.Рассмотрим следующую схему и средства разрешения:

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!',
  },
}

Если вы запросите все три поля ...

query {abc}

Ваши данные будут выглядеть примерно так:

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

Это потому, что GraphQL поддерживает частичные ответы.Однако имейте в виду, что это работает, потому что поля обнуляются.Если бы они были ненулевыми, эти ошибки всплыли бы до ближайшего родительского поля, которое можно обнулять .

Вот некоторые альтернативные подходы:

Выможет использовать formatError, чтобы изменить способ отображения ошибок, возвращаемых GraphQL, клиенту.Это означает, что вы можете включать в свои ошибки любую дополнительную информацию, такую ​​как код ошибки или несколько сообщений об ошибках.Простой пример:

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

Ваш ответ выглядит примерно так:

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

Тем не менее, есть что-то не очень приятное в возвращении сообщений об ошибках, связанных с пользователем, наряду с ошибками проверки GraphQL.Другой подход, который используют некоторые API, состоит в том, чтобы включить поле errors рядом с фактическим ответом на мутацию.Например:

type Mutation {
  userLogin: UserLoginResponse
}

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

Вы также можете использовать союзы для достижения аналогичного эффекта:

type Mutation {
  userLogin: UserLoginResponse
}

type Errors {
  errors: [String!]!
}

union UserLoginResponse = User | Errors
...