Skip to content

Latest commit

 

History

History
285 lines (233 loc) · 5.82 KB

graphql.md

File metadata and controls

285 lines (233 loc) · 5.82 KB

GraphQL

Responses:

Mutations:

Responses

How to understand errors

The GraphQL API always return a JSON body with the 200 status code, even when there are errors.

If an error occurred, the response body MUST include a top-level errors array that describes the error or errors as demanded by the GraphQL spec.

Errors can manifest as GraphQL validation errors (e.g. provided a string for an integer field), Kraken validation errors (e.g. invalid direct debit card number), or errors reflecting upstream issues.

{
  "errors": [
    {
      "message": "Could not find property",
      "locations": [
        {
          "line": 3,
          "column": 9
        }
      ],
      "path": ["property"],
      "extensions": {
        "errorClass": "NOT_FOUND"
      }
    }
  ],
  "data": {
    "property": null
  }
}

An element of the errors array follows the GraphQL spec and will have the following values:

  • message: The human-readable error message. This value is not intended to be parsed and may change at any time.
  • locations: An array of { "line": x, "column": y } objects that describe where the error was detected during parsing of the GraphQL query.
  • path: The GraphQL query or mutation causing the error.
  • extensions: Additional information about the error

For queries, it is possible to have partially successful responses, where both a partially populated data object and errors are returned. If errors prevent a field in your query from resolving, the field in the data object will be returned with the value null and relevant errors will be in the error object.

Error classes

AUTHORIZATION

Queries, Mutations: User access unauthorised

NOT_FOUND

Queries: Resource could not be found Mutations: Resource to update could not be found (E.g invalid id provided)

NOT_IMPLEMENTED

Queries, Mutations: Feature not implemented yet

SERVICE_AVAILABILITY

Queries, Mutations: An intermittent error due to an unavailable service

VALIDATION

Mutation: Validation error due to invalid input(s)

  • validationErrors: All validation errors
    • inputPath: The input field responsible for the error (Optional)
    • message: The human-readable error message
{
  "errors": [
    {
      "message": "Invalid inputs",
      "locations": [
        {
          "line": 3,
          "column": 9
        }
      ],
      "path": ["createUser"],
      "extensions": {
        "errorClass": "VALIDATION",
        "validationErrors": [
          {
            "inputPath": ["input", "user", "firstName"],
            "message": "Name too short"
          },
          {
            "inputPath": ["input", "user", "age"],
            "message": "Not a number"
          }
        ]
      }
    }
  ],
  "data": {
    "createUser": "None"
  }
}

No inputPath should be provided for validation errors where the inputs are valid individually but a combination of them are invalid (E.g direct debit details account number and sort code are individually valid but invalid together)

{
  "errors": [
    {
      "message": "Invalid inputs",
      "locations": [
        {
          "line": 3,
          "column": 9
        }
      ],
      "path": ["createUser"],
      "extensions": {
        "errorClass": "VALIDATION",
        "validationErrors": [
          {
            "message": "Invalid direct debit details"
          }
        ]
      }
    }
  ],
  "data": {
    "createUser": "None"
  }
}

Mutations

Begin names with action type

mutation CreateUserMutation($input: UserInputType!) {
  createUser(input: $input) {
    user {
      firstName
    }
  }
}

where

type User {
  firstName: String!
  lastName: String!
  age: Int!
}

mutation DeleteUserMutation($input: UserInputType!) {
  deleteUser(input: $input) {
    user {
      firstName
    }
  }
}

Use an input object type for the argument

mutation UpdateUserMutation($input: UserInputType!) {
  updateUser(input: $input) {
    user {
      firstName
    }
  }
}

where

type UserInputType {
    firstName: String!
    lastName: String!
    age: Int!
}

mutation UpdateUserMutation(
  $firstName: String!
  $lastName: String!
  $age: Int!
) {
  updateUser(firstName: $firstName, lastName: $lastName, age: $age) {
    user {
      firstName
    }
  }
}

Otherwise the mutations become more cumbersome to write out as the number of arguments grow Input object types are more flexible to changes. If the arguments change, less places need to be updated In the case where different mutations have the same arguments, the input object type can be reused.

mutation CreateUserMutation($input: UserInputType!) {
  createUser(input: $input) {
    user {
      firstName
    }
  }
}

Return an object in the payload

Ideally the object you've mutated If the returned object has the same global id as one stored in the apollo client cache, the UI using this data will be automatically updated with the latest data. Source

mutation UpdateUserMutation($input: UserInputType!) {
  updateUser(input: $input) {
    user {
      id
      firstName
      lastName
    }
  }
}

mutation UpdateUserMutation($input: UserInputType!) {
  updateUser(input: $input) {
    firstName
    lastName
  }
}