learn

REST API vs. GraphQL

Application programming interfaces (APIs) play an increasingly central role in distributed applications that rely on an interdependent mesh of microservices and third-party web services. With real-time data processing becoming mainstream across all industries, API performance and usability are ever more important to customer satisfaction. REST APIs and GraphQL are among the top contenders among the types of available APIs. Each has its strengths and weaknesses that make them appealing to different groups of developers, companies, and use cases. 

This article explores key differences and similarities between REST APIs and GraphQL. We also look at features, architecture, and recommendations based on the distinctions between the two technologies.

Summary of REST API vs. GraphQL differences

Category REST API GraphQL
Scalability Strong horizontal scalability Strong horizontal and vertical scalability
Flexibility Flexible for simple and less dynamic data More flexible for dynamic data
Error handling Specific error messages Less specific error messages, but predictable and consistent structure
Versioning Url-based, header-based, query parameter-based, or media-type-based Schema-based
Performance Can be optimized with caching Better optimized for data retrieval and caching.
Use cases Simple applications, large applications and microservices API gateways, micro-frontends, front-end-only applications, middlewares and back-end applications.

What are REST APIs?

REST APIs are a type of web API that leverage standard HTTP methods for clients to communicate with servers with standard HTTP methods, such as GET, POST, PUT, and Delete. To provide a practical example, below is a simple GET request to a hypothetical REST API endpoint and the response it returns. ​In this example, the API uses the endpoint /users/{id}, where {id} is the identifier of a specific user.

GET /users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer your_token

REST API GET Request for the user with an ID of 123. A typical response to this request looks like the following example.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 123,
    "name": "John Doe",
    "email": "john.doe@example.com",
    "role": "Administrator"
}

In the above response, the 200 OK status code indicates that the request was successful. The response body contains the data in JSON format, including the user's ID, name, email, and role.

What are GraphQL APIs? 

GraphQL is a query language and runtime for APIs. Its primary strength is equipping clients to make targeted requests for data from servers while also allowing for efficient and flexible data retrieval. GraphQL primarily uses POST, but in some instances uses GET. To demonstrate the flexibility and efficiency of GraphQL, let's look at a typical GraphQL query and the associated response.

query {
  user(id: "123") {
    id
    name
    email
    role
  }
}

The GraphQL API query asks for specific fields (id, name, email, role) for the user with an ID of 123. A typical response resembles the following example.

{
  "data": {
    "user": {
      "id": "123",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "role": "Administrator"
    }
  }
}

This GraphQL API response shows the specific fields of the response (id, name, email, role) for the user with an ID of 123. You can see the data object containing the requested user's details. This example demonstrates how GraphQL allows clients to request specific data fields, resulting in smaller, more efficient responses.

REST API vs. GraphQL: Key considerations 

REST APIs are designed with simplicity, efficiency, and scalability in mind. The primary principles of any REST API are uniform interface, statelessness, and cacheability. New or seasoned developers can learn REST quickly using its straightforward design, standard HTTP methods, and status codes.

In contrast, GraphQL has a very different design than REST APIs. Its strongly-typed schema provides clients with an easy-to-read and easy-to-understand overview of the available data operations. REST APIs and GraphQL each have their unique strengths and weaknesses. Below is a discussion of some of the critical differences.

Scalability

GraphQL has a declarative nature that contributes significantly to its scalability. It allows clients to make precise data requests and limits over-fetching of the data while optimizing resources. Additionally, you can make GraphQL requests for multiple resources in one query. It reduces the number of network requests and also helps to improve performance. These features of GraphQL equip it to scale well horizontally and vertically. Also, the scalability of your application can be influenced by factors such as architecture, requirements and usage patterns. These factors can play a crucial role in determining whether horizontal or vertical scaling with GraphQL would be more effective.

In contrast, REST APIs are stateless and loosely coupled. The client and server do not need to maintain state information about each other, which allows them to communicate independently. The stateless and loosely coupled nature of REST APIs allows them to efficiently scale horizontally by adding more servers to the cluster.

Flexibility

REST APIs are flexible because you can use them to fetch a wide range of data types and implement different types of functionality. The loosely coupled nature of REST APIs also makes them easy to upgrade. However, REST APIs are usually defined with a set of endpoints, and clients must know which endpoint to use for the requested data. This can be limiting in a highly dynamic environment where data requirements constantly change.

GraphQL is more flexible than REST APIs when it comes to requesting data. GraphQL allows clients to request data in various ways, including fields, arguments, and fragments. This makes GraphQL a great fit for environments with more dynamic data needs.

Use cases

REST APIs and GraphQL are designed differently, so they are better suited for different types of applications. REST APIs are a good choice for applications that need to retrieve static data or for applications with simple data requirements that don’t change often. GraphQL is a good choice for applications that need to retrieve dynamic data or for applications with frequent changes in data requirements. For example:

  • Static Data: A REST API would be a good choice for an application that needs to retrieve a list of products from a database that aren’t updated often - such an application for a seasonal, holiday company that sells homegoods and only updates its products once a year.
  • Dynamic Data: A GraphQL API would be a great choice for more dynamic data - such as a GPS navigation app that provides users directions based on real time location data.
  • Simple Data Requirements: A REST API is a good choice for applications where the data requirements are simple- such as an application for a daily todo list.
  • Complex Data Requirements: A GraphQL API would be a good choice for more complex data requirements- such as social media application that supports a wide variety of complex data sources, such as live streaming, profile info, likes, comments, GPS info and product info for recommending products based on user interaction with the platform.

{{banner-28="/design/banners"}}

REST API vs. GraphQL: Implementation differences

Below are some differences to consider when implementing REST and GraphQL APIs.

Error handling

REST APIs and GraphQL also differ in their approach to error handling. Error handling is one of the major strengths of REST APIs. They provide specific errors that help tremendously in debugging and troubleshooting errors. Let’s consider the following example of a REST API error response.

{
  "status": 404,
  "error": "Not Found",
  "message": "User with the ID 3 not found."
}

In this REST API error response, the error indicates that the requested resource (user with an ID of 3) was not found on the server, which led to the 404 “Not Found” response. 

In contrast, GraphQL API error messages are not as specific. They require more investigation to understand the root cause of the issues. However, GraphQL API errors do return a predictable and consistent structure that helps with debugging and troubleshooting in other ways.

{
  "errors": [
    {
      "message": "Name for the user with ID 1002 could not be fetched.",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["user", "family", 1, "name"]
    }
  ],
  "data": {
    "user": {
      "name": "R2-D2",
      "family": [null, {"name": "Han John"}]
    }
  }
}

In this GraphQL API error response, the error indicates that the name for the user with the ID of 1002 could not be fetched from the path “user.family[1]” at line 6.

Versioning

REST APIs rely on updating the URL to show different API versions. This can lead to challenges when a REST API undergoes regular and/or significant changes. REST APIs also have other ways of implementing versioning, such as header-based versioning, query parameter-based versioning, and media type-based versioning. A REST API could have different versions indicated in the URL, like the following example.

https://api.example.com/v1/users
https://api.example.com/v2/users

Unlike REST APIs, GraphQL doesn’t rely on traditional schema versioning. When faced with the need to delete an entire type, such as “User” type, GraphQL and REST API use different approaches. GraphQL uses a gradual deprecation process, allowing fields to be marked as deprecated, signaling to clients to migrate away without immediate disruption. The introspection feature empowers clients to dynamically adapt their queries based on the evolving schema, though coordination between server and client teams is essential. 

Additionally, GraphQL’s inherent flexibility enables the introduction of new types or changes without versioned endpoints, streamlining transition management. In contrast, traditional REST APIs often rely on versioned endpoints, requiring explicit version specifications in the URIs. The deletion of a type in REST may result in immediate disruption, contrasting with GraphQL’s more adaptable and phased deprecation approach. Refer to the following example, to understand how schema versioning for a GraphQL API looks like.

// Version 1
type User {
  id: ID!
  name: String!
  email: String!
}
// Version 2
type User {
  id: ID!
  name: String!
  email: String!
  age: Int
}

 In this code block, the code represents two versions of a GraphQL schema for the “User” type. “Version 2“ includes an additional “age” field compared to “Version 1”.

{{banner-29="/design/banners"}}

REST API vs. GraphQL: Performance

REST APIs and GraphQL each have their performance strengths.

GraphQL’s data retrieval and caching mechanisms significantly optimize its performance. Clients precisely request only the data they need, which reduces the payload size and results in faster response times. An example GraphQL query for fetching user data is shown below.

query {
  user(id: "1") {
    name
    email
    posts(limit: 5) {
      title
      content
      comments(limit: 3) {
        text
        author {
          name
          email
        }
      }
    }
    friends {
      name
      email
      posts(limit: 2) {
        title
      }
    }
  }
}

The above GraphQL API query retrieves example user information from a social media profile, where the data is stored in multiple locations. The data fetched includes the name, email, recent posts with comments, friends’ data, and their friend’s recent posts. As you can see, GraphQL uses a nested approach that allows for data from multiple locations to be fetched in a single query.

{
  "data": {
    "user": {
      "name": "John Doe",
      "email": "john.doe@example.com",
      "posts": [
        {
          "title": "First Post",
          "content": "Check out my new dog Waffles. He had a blast at the park today.",
          "comments": [
            {
              "text": "Cute dogie!",
              "author": {
                "name": "Alice",
                "email": "alice@example.com"
              }
            },
            {
              "text": "I look forward to meeting him when I visit you! I'm going to bring him some dog treats.",
              "author": {                "name": "Josh",
                "email": "Josh@example.com"
              }
            },
            {
              "text": "Looking forward to more.",
              "author": {
                "name": "Eve",
                "email": "eve@example.com"
              }
            }
          ]
        },
        {
          "title": "Second Post",
          "content": "Does anyone know a good dog groomer? Waffles could use some grooming.",
          "comments": [
            {
              "text": "Pet Palace on 21st Street is great.",
              "author": {
                "name": "Charlie",
                "email": "charlie@example.com"
              }
            },
            {
              "text": "What kind of services are you looking to get?",
              "author": {
                "name": "Dave",
                "email": "dave@example.com"
              }
            },
            {
              "text": "Furside Grooming is really good.",
              "author": {
                "name": "Frank",
                "email": "frank@example.com"
              }
            }
          ]
        }
      ],
      "friends": [
        {
          "name": "Jane Smith",
          "email": "jane.smith@example.com",
          "posts": [
            {
              "title": "Vacation Photos",
              "content": "Sharing some beautiful vacation photos."
            },
            {
              "title": "Recipe of the Day",
              "content": "Here's a delicious recipe to try."
            }
          ]
        },
        {
          "name": "Mary Johnson",
          "email": "mary.johnson@example.com",
          "posts": [
            {
              "title": "Book Recommendations",
              "content": "Some great books I've been reading lately."
            },
            {
              "title": "Gardening Tips",
              "content": "Tips for maintaining a healthy garden."
            }
          ]
        }
      ]
    }
  }
}

Only the requested fields are returned even if the user object contains more fields. This efficient approach of querying is a result of how GraphQL employs application-level and fine-grained caching to optimize data retrieval.

REST APIs also have performance strengths. REST APIs often use response-based caching and stateless caching to reduce the number of requests that need to be made to the server. 

Over-fetching and under-fetching in REST

In some scenarios, REST APIs may face some performance challenges due to over-fetching or under-fetching. A REST API query for fetching user data could look like the following. To request the same information as the GraphQL API from multiple sources, the REST API would have to typically use multiple HTTP requests to the different endpoints to fetch data from the various locations.

GET /users/1

It is a GET request to retrieve user data with the ID “1” from the “api.example.com” endpoint. The response is as shown below.

{
  "id": "1",
  "name": "John Doe",
  "email": "johndoe@example.com",
  "address": "123 Main St",
  "phoneNumber": "123-456-7890"
}

This example, REST API response from the GET request shows the results for the “id”, “name”, “email”, “address” and “phoneNumber” for the “id” of 1. The result includes unnecessary details of the user's address and phone number. These additional items that were fetched are an illustration of overfetching. In contrast, if there were additional features that needed to be fetched, and they were not fetched, this would have been underfetching. The additional information would have to be fetched with additional queries. One of the additional queries is shown below. For the remainder of the information, such as comments from other users and the friends of the users, a separate query would need to be made for each.

GET /users/1/posts?limit=5

This query would fetch the information for the posts from the user.

[
  {
    "id": "101",
    "title": "First Post",
    "content": "Check out my new dog Waffles. He had a blast at the park today."
  },
  {
    "id": "102",
    "title": "Second Post",
    "content": "Does anyone know a good dog groomer? Waffles could use some grooming."
      }
]

This response shows the results for the posts query for the user content.

{{banner-30="/design/banners"}}

Resolving REST performance concerns

You can apply the below techniques to mitigate REST performance issues. While they don’t completely resolve the over-fetching issue, they can help to ameliorate concerns. (Note: The best, direct solution for overfetching or underfetching is thoughtful consideration of the design and architecture of your API.)

Selective field queries in REST

You can use query parameters to customize the response. Clients request only the specific fields they need.

Challenges:

  • Requires careful API design and more detailed documentation to guide clients on available query parameters.
  • May make the API more challenging to manage and maintain.

Response shaping in REST

You can use query parameters or headers to shape the returned data, allowing clients to define the structure of the response.

Challenges:

  • Also, requires detailed documentation to help the clients navigate the available response shaping options.
  • Introduces additional complexity in handling dynamic response structures

Use a caching mechanism

A caching mechanism enhances REST API performance and reduces the redundant data retrieval. It doesn’t directly solve the overfetching problem, as cached data inherently includes more information than the client requests.

{{banner-31="/design/banners"}}

Specify the data required by the client

This is an inherent strength of GraphQL, that requires a workaround in REST. More specificity can be achieved by creating additional separate endpoints.  It allows clients to precisely specify the data needed, which helps to minimize overfetching.
Challenges: 

The approach to increase specificity and decrease overfetching, can simultaneously increase the complexity of the API structure and make it more challenging to manage.

Use a pagination-supported client

This a tremendous help to managing large datasets in the presentation layer and can help to create a smoother user experience.

While it doesn't directly resolve the overfetching at the API level, it can be very helpful when dealing with large amounts of data and optimizing the user experience.

Tools to work with REST and GraphQL APIs

REST APIs are a mature design pattern with an abundant ecosystem of tools, integrations, and learning resources. Their wide adoption makes them an excellent choice for integrating with both novel and legacy systems. According to a number of recent surveys, including the annual developer survey by StackOverflow, engineering teams generally prefer REST APIs to launch new products or extend existing product capabilities with API development. Some popular tools for REST API development include Postman, Insomnia, Flask, and RESTify.

In contrast, GraphQL is a newer technology that has only grown to wider adoption in recent years. It is still growing in terms of integration, community, and resources. GraphQL resources are found on Discord, Telegram, Medium, and various GitHub communities. Some popular tools for GraphQL development include GraphQL Playground, Apollo Studio, GraphiQL, and GraphQL Yoga.

{{banner-32="/design/banners"}}

GraphQL and REST API Monitoring

For both REST API and GraphQL development, leveraging proper monitoring tools is essential. The right tools can provide valuable insight into the overall API performance and assist in optimizing the API and the components in the API’s pathway. Catchpoint is a great tool that can serve these needs for any API project. 

Catchpoint is an efficient tool for both GraphQL and REST API monitoring. It offers a comprehensive insight into metrics such as cache latency, cache errors, cache utilization, and cache hit ratio. Developers can trace components along the API transaction path, such as DNS and public internet, using both real-user monitoring (RUM) and synthetic monitoring. These distinct features and an enhanced user experience set Catchpoint apart from open-source alternatives like Prometheus.

Catchpoint has many other advantages:

  • Out-of-the-box monitoring
  • Streamlined performance profiling for granular issue investigation
  • Trace analysis for visualizing request flows to identify specific performance challenges 
  • Smooth integration with key tools like Jira, Slack, and Splunk. 

By using Catchpoint, engineers can pinpoint bottlenecks across the end-to-end transaction path spanning the sections they control, like the microservices and database service, and the sections that rely on third-party service providers like DNS, content delivery network (CDN), and internet transit points, while keeping an eye on the end-user experience in the application user-interface. This type of fault isolation capability shortens troubleshooting and helps improve the application’s overall performance and security. 

Another advantage of Catchpoint’s API monitoring solution is that it’s based on the OpenTelemetry framework, which is a vendor-neutral approach to tracing, logging, and monitoring application and API metrics designed to avoid user dependence on proprietary technologies.

Conclusion

APIs are essential in today’s rapidly evolving technology landscape, facilitating efficient and scalable interactions between software systems and services. Making the right API technology and tooling choices is crucial for project success. Choosing between REST API vs. GraphQL requires careful evaluation of your company's needs and your specific project. GraphQL offers flexibility and precise data retrieval, while REST APIs excel in simplicity and scalability. 

Maximize your project’s potential by embracing the power of different API types and leveraging the right tools for optimized performance as you and your team continue your API development journey.

What's Next?