Graphql / Apollo Ошибки иногда выводят data: null иногда data: {function: null}

Я настраиваю тестирование для своего graphql. При этом я понимаю, что иногда объект данных в случаях ошибки выводится следующим образом:

{
   errors: [...],
   data: null
}

и иногда :

{
     errors: [...],
     data: {
        updateCity: null
    }
}

Эти тесты касаются мутаций. Это пример обоих кодов:

случай резольвера 1:

 updateUser(parent, args, context, info) {
      logger.debug('Mutation > updateUser resolver');
      return userController.user.update.user(parent, args.userInfo, context, info);
    },

случай схемы 1:

extend type Mutation {
    updateUser(userInfo: UserInfo!): User!
}

корпус контроллера 1:

user: async (parent, args, context, info) => {
    try {
      logger.debug('User Controller : update User');
      await controller.validate(args);
      const userModel = new UserModel('member');
      if (!(await userModel.findOne(args.id))) errorscb.userInputError('User does not exist');
      let id = args.id;
      let newArgs = args;
      delete newArgs.id;
      return userModel.updateById(id, newArgs);
    } catch (e) {
      logger.warn({ stack: e.stack, message: e.message });
      throw e;
    }
  },

случай схемы 2:

extend type Mutation {

    updateCity(id: Int!, name: String, countryId: Int): City
}

случай резольвера 2:

updateCity(obj, args, context, info) {
      logger.info('City > updateCity resolver');
      return cityController.city.update.city(obj, args, context, info);
    },

корпус контроллера 2:

city: async (parent, args, context, info) => {
    try {
      logger.info('City Controller : update city');

      await controller.validate(args);
      const cityModel = new CityModel('city');
      if (!(await cityModel.findOne(args.id))) 
          errorscb.userInputError('City does not exist');
      let id = args.id;
      let newArgs = args;
      delete newArgs.id;
      return cityModel.updateById(id, newArgs);
    } catch (e) {
      logger.warn({ stack: e.stack, message: e.message });
      throw e;
    } 

Я хотел бы получить согласованный результат, кто-нибудь знает, как это исправить?


person GiiiZz    schedule 27.04.2019    source источник


Ответы (2)


Это действительно ожидаемое поведение.

Разница между updateUser и updateCity в вашем заключается в том, что последний возвращает тип, допускающий значение NULL (City), а первый возвращает ненулевой тип (User!). Разница в ответах возникает из-за того, что ошибки распространяются по ответу до тех пор, пока не попадут в поле, допускающее значение NULL. Из спецификации:

Если при разрешении поля возникает ошибка, ее следует рассматривать так, как если бы поле вернуло значение null, и ошибку необходимо добавить в список ошибок в ответе.

Если результат разрешения поля равен нулю (либо потому, что функция для разрешения поля вернула значение null, либо потому, что произошла ошибка), и это поле имеет тип, отличный от Null, возникает ошибка поля. Ошибка должна быть добавлена ​​в список ошибок в ответе.

...

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

Другими словами, выдавая ошибку во время разрешения поля, мы фактически разрешаем этому полю значение null. Но когда мы сообщаем GraphQL, что поле имеет тип, отличный от Null, и это поле разрешается в null, GraphQL не может вернуть поле со значением null (потому что это нарушит контракт схемы). Таким образом, все родительское поле становится нулевым. Если родительское поле также не допускает значения NULL, оно обнуляет родительское поле этого поля и так далее ... до тех пор, пока оно не достигнет поля, допускающего значение NULL, или корня запроса (поле data).

Сравните: Схема 1

type Query {
  a: A
}

type A {
  b: B
}

type B {
  c: String
}

Схема 2

type Query {
  a: A
}

type A {
  b: B
}

type B {
  c: String!
}

Схема 3

type Query {
  a: A!
}

type A {
  b: B!
}

type B {
  c: String!
}

Если мы запрашиваем поле c и распознаватель для поля c throws, мы получим следующие ответы:

Схема 1

{
  "data": {
    "a": {
      "b": {
        "c": null
      }
    }
  }
}

Схема 2

{
  "data": {
    "a": {
      "b": null
    }
  }
}

Схема 3

{
  "data": null
}
person Daniel Rearden    schedule 27.04.2019

extend type Mutation {
    updateUser(userInfo: UserInfo!): User!
}

Нашел исправление, требующее, чтобы Пользователь был ненужным, и удаление восклицательного знака устранило мою проблему (а ... каким-то образом)

updateUser (userInfo: UserInfo!): Пользователь !

person GiiiZz    schedule 27.04.2019