DEV Community

Cover image for GraphQL vs. REST
Jake Barnby for Appwrite

Posted on • Edited on

GraphQL vs. REST

GraphQL and REST are two different approaches to implementing web APIs that allow clients to access data from a server.

While both approaches have their own advantages and disadvantages, they are often used to solve similar problems and can sometimes be used interchangeably. Today we’ll cover some of the differences between the two.

Requests

One of the key differences between GraphQL and REST is the way that data is accessed. In REST, data is typically organized into a set of resources, each with its own unique URL.

For example, if an API exposes information about users and their addresses, there might be separate URLs for accessing user data and address data, such as:

Get user profile by ID: https://example.com/users/{id}
Get user address by ID: https://example.com/addresses/{id}

To retrieve data, a client would make a request to one of these URLs using an HTTP method such as GET, POST, PUT, or DELETE.

In contrast, GraphQL uses a single endpoint for all data requests. To retrieve data, a client sends a GraphQL query to this endpoint, specifying the data they want to retrieve. The server then responds with the requested data in a JSON object.

Here is an example of a GraphQL query that could be used to retrieve information about a user with a given ID:

query {
    usersGet(id: "abc123") {
        name
        email
        addresses {
            city
            country
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the query keyword indicates that we are making a query to the server, meaning no data will be modified, and the user and address fields specify the data we want to retrieve. The id argument allows us to specify which user we want to retrieve data for.

The server will respond with a JSON object containing only the requested data, like this:

{
    "data": {
        "user": {
            "name": "John Doe",
            "email": "johndoe@example.com",
            "addresses": [
                {
                    "city": "New York",
                    "country": "USA"
                },
                {
                    "city": "Houston",
                    "country": "USA"
                }
            ]
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

By comparison, here are examples of REST requests that could be used to retrieve the same information:

GET https://example.com/users/abc123
Enter fullscreen mode Exit fullscreen mode

The server would first respond with a JSON object containing the user data, like this:

{
    "name": "John Doe",
    "email": "johndoe@example.com"
}
Enter fullscreen mode Exit fullscreen mode

To then retrieve the user's addresses, the client would need to make another request to a different URL, like this:

GET https://example.com/users/abc123/addresses
Enter fullscreen mode Exit fullscreen mode

The server would then respond with a JSON object containing the address data, like this:

[
    {
        "city": "New York",
        "country": "USA"
    },
    {
        "city": "Houston",
        "country": "USA"
    }
]
Enter fullscreen mode Exit fullscreen mode

As you can see, the GraphQL approach allows the client to specify the exact data they want to retrieve, while the REST approach requires the client to make multiple requests to different URLs to retrieve the same data.

This can be more efficient for the client, as it allows them to retrieve everything in a single round trip to the server.

Structure

Another key difference between GraphQL and REST is how data is structured on the server.

In REST, the structure of the data is determined by the URL hierarchy and the HTTP methods used to access it. For example, in the REST example above, the user and address data are accessed through different URLs, and the POST method is used to create new addresses.

In GraphQL, the structure of the data is determined by the schema defined on the server. The schema defines the types of data that can be accessed, as well as the fields and relationships between those types. For example, the types for the user and address data might be defined in the schema like this:

type User {
    id: ID!
    name: String!
    email: String!
    addresses: [Address!]!
}

type Address {
    id: ID!
    city: String!
    country: String!
}
Enter fullscreen mode Exit fullscreen mode

These types define the structure of the user and address data respectively. The [] symbols denote a list of the enclosed type, and the ! symbol indicates a non-nullable field.
In addition to the User and Address types, there must always be a Query type, and optionally a Mutation type. These two special types define all queries a client can execute, for example:

type Query {
    userGet(id: String!): User
    addressGet(userId: String!): Address
}

type Mutation {
    userCreate(
        name: String!,
        email: String!
    ): User

    addressCreate(
        userId: String,
        city: String!,
        country: String!
    ): Address
}
Enter fullscreen mode Exit fullscreen mode

With this schema in place, the client can use GraphQL to access and modify the user and address data in a consistent and predictable way. For example, they could use the following mutation to create a new address:

mutation {
    addressCreate(
        userId: "abc123"
        city: "Cleveland"
        country: "USA"
    ) {
        id
        city
        country
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the mutation keyword indicates that we are modifying data on the server, and the addressCreate field specifies the data we want to create. The arguments allow us to specify the values for the new address, and the id, city, and country fields specify the data we want to retrieve for the new address. The server would respond with a JSON object containing the newly created address data, like this:

{
    "data": {
        "addressCreate": {
            "id": "def456",
            "city": "Cleveland",
            "country": "USA"
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

If the client did not need the address id, or any other field, it could be excluded from the field selection, and it would not be included in the response.
In a REST API, the client would need to make a POST request to a specific URL to create a new address, like this:

POST https://example.com/addresses

{
    "userId": "abc123",
    "city": ”Cleveland",
    "country": “USA"
}
Enter fullscreen mode Exit fullscreen mode

Efficiency

In some cases, it would be useful to create multiple resources at the same time. GraphQL allows this in a single request with query batching. Given the schema above, you could create multiple addresses for the same user in the same request with the following mutation:

mutation {
    address1: addressCreate(
        userId: "abc123"
        city: "Cleveland"
        country: "USA"
    ) {
        city
    }

    address2: addressCreate(
        userId: "abc123"
        city: "Seattle"
        country: "USA"
    ) {
        city
    }
}
Enter fullscreen mode Exit fullscreen mode

Because we are requesting the result of two addressCreate fields, we need a way to distinguish them in the response data. This mutation uses a concept called aliasing to give different names to two field executions of the same name. Given this query, the server would respond with:

{
    "data": {
        "address1": {
            "city": "Cleveland"
        },
        "address2": {
            "city": "Seattle"
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

To achieve the same result with REST, two consecutive requests would be made to the POST address endpoint.

Errors

In GraphQL, error handling is done using the errors key in the response object. Every response will use a status code of 200 OK, and the server will include any errors that occurred during the query in the errors array. The data object entry for the field that encountered an error will have a null value, and the error object will include the key in the path array. This allows the client to identify any issues that may have occurred and handle them appropriately. For example, if creating an address failed because a user did not exist, the response might look like this:

{
    "data": {
        "addressCreate": null
    },
    "errors": [
        {
            "message": "User does not exist",
            "path": [
                "addressCreate"
            ]
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

For a REST API, error handling is typically done using HTTP status codes. When an error occurs, the server will include the corresponding status code in the response. The client can use this to determine what type of error has occurred and handle it accordingly, regardless of whether the response includes a more descriptive message.

Overall, the main difference between the two approaches is that GraphQL provides more textual information about the errors that have occurred, while REST relies on standardized HTTP status codes.

Caching

Web caching is a technique used to improve the performance and scalability of web applications by storing frequently accessed data in a cache. This can help reduce the number of requests made to the server and improve the overall response time of the application.

With GraphQL, web caching is typically handled using a technique called "query caching". This involves storing the results of frequently-accessed queries in the cache, and returning the cached results when the same query is made again. This can greatly improve the performance of a GraphQL API, as it reduces the number of times the server has to execute the same query. Implementing a query cache requires a custom implementation which may not be trivial to develop.

In a REST API, web caching is typically handled using HTTP caching headers. These headers can be included in the response from the server to indicate whether and for how long the client can cache the response. The client can then use this information to store the response in a cache and return the cached data when the same request is made again, reducing the number of requests made to the server and improving the overall response time.

Which Do I Choose?

GraphQL is designed to enable clients to access and manipulate data in a more flexible and powerful way than is possible with REST. In particular, GraphQL allows clients to specify exactly which data they need, and the server will return only that data, in a single request. This can make it easier for clients to access and manipulate data and improve the API's performance and scalability.

On the other hand, REST is a more established and widely-used approach to building APIs, and it has a large ecosystem of tools and libraries that support it. This means that it is often easier to get started with REST, and it can be more straightforward to integrate with existing systems and infrastructure.

GraphQL and REST have unique strengths and weaknesses, and the best choice for a particular project will depend on the specific requirements and use cases. It is important to carefully evaluate both options and choose the one best suited to the project's needs.

Learn more

You can use the following resources to learn more and get help:
🚀 Appwrite Github
📜 Appwrite Docs
💬 Discord Community

Top comments (0)