Software Artist’s blog

Keep it simple!

Advantages & Disadvantages of GraphQL

If you are looking for what GraphQL is then please read this first post from our GraphQL series.

GraphQL is strongly typed like SQL queries. Each GraphQL query corresponds to a particular query type and each type has particular set of fields defined.

Even though GraphQL is a buzzword these days it should be checked for the feasibility of our use case. If advantages are winning over the disadvantages in our particular use case then definitely it will be helpful.

Following are some advantages and disadvantages of GraphQL which can help you decide.

Advantages

Single API Endpoint

GraphQL uses a single REST API endpoint for CRUD operations. The endpoint uses POST HTTP method and mostly it is /graphql.

It helps the API client to maintain a single API endpoint for every operation and reduces dependency on the backend team.

Selective Data Fetching

GraphQL was developed to solve the problem of over-fetching and under-fetching. We can fetch only the required fields for the resources as well as related resources.

Suppose we are having a UI component where we are displaying a list of tasks with only title and status. In that case, with REST API we will fetch all the tasks data through /tasks.json endpoint.

The response will have multiple data fields for the tasks which are not required in the context. We simply ended up fetching unnecessary data. Also, if some of the required fields are missing the then a new API endpoint would have to be requested to the backend team or an existing API endpoint will need an update.

In this case, GraphQL helps to target the API over and under fetching problem.

Performance

It helps to fetch the information of a resource on the field level. A REST API fetches all the data which the API endpoint has defined. In GraphQL, we can specify the fields that need to be retrieved which minimizes data transfer and database queries.

Consider the above example again. In the above example, the REST API will return activities and other data related to the tasks. But with GraphQL, it will not fire a database query to fetch the related data unless and until it is requested.

It is also performant while doing update operations. Instead of sending different requests, we can update multiple resources from a single request and ask for particular fields in the response.

Versioning

GraphQL solves the problem of versioning the APIs. We can add new fields and types to the GraphQL API at any time. It will not impact existing queries.

If there are aged fields then those can be deprecated and hidden from API tools/schema. Having a single version that is continuously evolving, gives client apps continuous access to new features. Also, it encourages cleaner and more maintainable server code.

Suitability For Microservices

GraphQL schema can work as an abstraction for integrating multiple microservices to hide the complexity.

One GraphQL schema can be defined and it will provide unified interface for multiple microservices where it will internally makes requests to multiple microserves and a merged response can be returned.

Schema Enabled

GraphQL API is schema enabled. By looking at the query we can know what type of objects are going to be returned.

We can have a GraphQL schema language implementation that allows talking about GraphQL schemas in a language-agnostic way.

Automatic Schema Generation

GraphQL automatically generates schema documentation. It can be accessed through Grpahql explorer.

Also, we can fetch the schema using GraphQL queries.

For fetching query types schema, following query can be used.

{
  __schema {
    queryType {
      fields {
        name
      }
    }
  }
}

The above query will fetch all the available query types.

{
  "data": {
    "__schema": {
      "queryType": {
        "fields": [
          {
            "name": "address"
          },
          {
            "name": "addresses"
          },
          {
            "name": "users"
          },
          {
            "name": "user"
          },
          {
            "name": "userProfile"
          },
          {
            "name": "activity"
          },
          {
            "name": "activities"
          }
        ]
      }
    }
  }
}

For fetching mutation types schema, following query can be used.

{
  __schema {
    mutationType {
      fields {
        name
      }
    }
  }
}

Tha above query will fetch all the mutation types.

{
  "data": {
    "__schema": {
      "mutationType": {
        "fields": [
          {
            "name": "cancelUser"
          },
          {
            "name": "createActivity"
          },
          {
            "name": "updateUser"
          },
          {
            "name": "updateActivity"
          },
          {
            "name": "modifyUserProfile"
          }
        ]
      }
    }
  }
}

Disadvantages

HTTP Code 200

GraphQL API returns HTTP code 200 for every request even though there is an error.

It returns the error in the error object of the response. It will put an extra effort on the API client for the error handling.

Complexity

If your application is using simple REST APIs which rely on consistent data then it is better to stick to the REST APIs. Using GraphQL API unnecessarily can lead to complexity.

Also, sometimes there is too much nesting of the requested parameters.

In case of the projects with rapid change in the data requirement GraphQL will prove to be helpful over the issues faced with REST APIs.

Lack Of Caching Support

In the endpoint based API endpoints it is quiet easy to use HTTP caching. Also, it can be identified if the resources are the same to avoid refetching. The API URLs help to identify unique requests.

In GraphQL, the API endpoint is always the same so it is not straightforward to identify the request and cache.

No Rollback on Mutations Failure

With GraphQL, we can execute multiple mutations through a single mutaiom operation like this.

mutation CreateTask(
  $taskName: String!,
  $activityType: String!,
  $activityDuration: String!,
  $taskDetails: String!
)
{
 createActivity
   (
     activityType: $activityType,
     activityDuration: $activityDuration,
   )
   {
     activityDuration
     id
   }
 createTask
   (
     taskName: $taskName,
     taskDetails: $taskDetails,
   )
   {
     taskName
     taskDetails
   }
}

#variables
{
    "taskName": "Financial assessment",
    "activityType": "Financial",
    "activityDuration": "3232343432",
    "taskDetails": "Financial assessment audit for the year 21-22"
}

Here, createActivity and createTask are two separate mutations. But if the mutation createTask fails then the executed createActivity mutation won’t rollback. That needs to be handled explicitly.