How to return both error and data in a graphql resolver?

Is it possible to solve this problem without adding error field to the return type?

Unfortunately, no.

A resolver can either return data, or return null and throw an error. It cannot do both. To clarify, it is possible to get a partial response and some errors. A simple example:

const typeDefs = `
  type Query {
    foo: Foo
  }

  type Foo {
    a: String
    b: String
  }
`
const resolvers = {
  Query: {
    foo: () => {},
  }
  Foo: {
    a: () => 'A',
    b: () => new Error('Oops!'),
  }
}

In this example, querying both fields on foo will result in the following response:

{
  "data": {
    "foo": {
      "a": "A",
      "b": null
    }
  },
  "errors": [
    {
      "message": "Oops",
      "locations": [
        {
          "line": 6,
          "column": 5
        }
      ],
      "path": [
        "foo",
        "b"
      ]
    }
  ]
}

In this way, it's possible to send back both data and errors. But you cannot do so for the same field, like in your question. There's a couple of ways around this. As you point out, you could return the errors as part of the response, which is usually how this is done. You could then use formatResponse, walk the resulting data, extract any errors and combine them with them with any other GraphQL errors. Not optimal, but it may get you the behavior you're looking for.

Another alternative is to modify the mutation so it takes a single memberId. You can then request a separate mutation for each id you're adding:

add1: addMemberToTeam(memberId: $memberId1 teamId: $teamId): {
  id
}
add2: addMemberToTeam(memberId: $memberId2 teamId: $teamId): {
  id
}
add3: addMemberToTeam(memberId: $memberId3 teamId: $teamId): {
  id
}

This can be trickier to handle client-side, and is of course less efficient, but again might get you the expected behavior.


If you think about combining the GraphQL error - there is a way to do it in Apollo. You need to set errorPolicy to all. That will help you notify users about the error and at the same time have as much data as possible.

none: This is the default policy to match how Apollo Client 1.0 worked. Any GraphQL Errors are treated the same as network errors and any data is ignored from the response.

ignore: Ignore allows you to read any data that is returned alongside GraphQL Errors, but doesn’t save the errors or report them to your UI.

all: Using the all policy is the best way to notify your users of potential issues while still showing as much data as possible from your server. It saves both data and errors into the Apollo Cache so your UI can use them.

But according to best practices, you shouldn't manipulate it in this way. This is a great article about handling errors in GraphQL.

So, preferable way is to add "errors" field as part of your response and handle it in JS code.


We can achieve this by using a union. I would recommend visiting the great article Handling GraphQL errors like a champ

Example:

Mutation part: We can return the union type for the response & capture the result according to types.

type MemberType {
  id: ID!
  name: String!
}

enum ErrorType {
  BAD_REQUEST_ERROR
  FORBIDDEN_ERROR
  INTERNAL_SERVER_ERROR
  NOT_FOUND_ERROR
  UNAUTHORIZED_ERROR
}

type GraphqlError {
  type: ErrorType!
  code: String!
  message: String!
  helpLink: URL
}


union UserRegisterResult = MemberType | GraphqlError;
addMembersToTeam(membersIds: [ID!]! teamId: ID!): UserRegisterResult!

Response:

addMembersToTeam(membersIds: [ID!]! teamId: ID!): {
...on MemberType{
  id,
  name,
}
...on GraphqlError{
  id,
  message,
  statusCode,
}
}