0%

Getting Started With GraphQL

What is GraphQL? The draft RFC specification (October 2016), defines it as “a query language created by Facebook in 2012 for describing the capabilities and requirements of data models for client‐server applications”. More simply, GraphQL is a language specification for API. It defines in which way the client should query the server, and in which way the server should execute those queries.
From the definition above, it is clear that GraphQL can be adopted as an alternative to REST. Let’s now analyze its features with an example in order to understand GraphQL base concepts.
Think about your favourite website for booking hotel rooms, that is obviously hotels.com, and let’s try to design a GraphQL service that provides the reservation list for a specific user.

Data model

The first thing to do is defining the graph of the data provided by the service.
The data model we are going to define follows this structure:
+--------------------------------------+         +----------------------------+         +---------------------+
| QueryType                            |         | ReservationType            |         | HotelType           |
+--------------------------------------+         +----------------------------+         +---------------------+
|                                      |         |                            |         |                     |
| reservationList: [ReservationType!]! +-------> | hotelId: ID!               |         | hotelName: String!  |
|                                      |         | checkIn: String!           |         | fullAddress: String |
+--------------------------------------+         | checkOut: String!          |         | starRating: Int!    |
                                                 | hotelDetails: HotelType!   +-------> |                     |
                                                 | status: ReservationStatus! |         +---------------------+
                                                 |                            |
                                                 +----------------------------+

GraphQL models your data as a graph but it still needs entry points to that graph. Those entry points are the queries defined in the QueryType, that is the root of all the queries.
In this example, it is defined only one query named “reservationList” that returns a list of “ReservationType”. In turn, ReservationType describes a hotel reservation and HotelType describe a hotel.

GraphQL Schema definition

Using the “GraphQL schema language“, explained in the official GraphQL website, our data model can be described in this way:

schema {
    query: QueryType
}

type QueryType {
reservationsList(userId: ID!): [ReservationType!]!
}

type ReservationType {
hotelId: ID!
checkIn: String!
checkOut: String!
hotelDetails: HotelType!
status: ReservationStatus!
}

type HotelType {
hotelName: String!
fullAddress: String
starRating: Int!
}

enum ReservationStatus {
UPCOMING
COMPLETED
CANCELLED
}

In very short, in this graphql schema definition we have:

This GraphQL schema can be parsed in order to be used for a real service. For instance, Apollo “graphql tools” is a javascript utility for parsing such a schema.

Query example

This is an example of a query, valid for our schema:
1
{
2
  reservationsList(userId: 12345) {
3
    hotelId
4
    checkIn
5
    checkOut
6
    hotelDetails {
7
      hotelName
8
      fullAddress
9
      starRating
10
    }
11
    status
12
  }
13
}

This query is sent from the client to the server in order to request the list of hotel ids in which the user number 12345 has made a reservation. Once the server receives this query, it is validated against the defined schema and then it is executed.

Response example

The generated response is JSON with the exact shape of the request:

1
{
2
  "data": {
3
    "reservationsList": [
4
      {
5
        "hotelId": "103",
6
        "checkIn": "2018-11-29",
7
        "checkOut": "2018-11-30",
8
        "hotelDetails": {
9
          "hotelName": "Hotel Campanile Metz Nord - Talange",
10
          "fullAddress": "Zone Actipole, Talange, Moselle, 57525, France",
11
          "starRating": 5
12
        },
13
        "status": "UPCOMING"
14
      }
15
    ]
16
  }
17
}
Please note that the client asks only for the data it needs, and with only one query. This is an advantage of using GraphQL because, in general, it reduces the number of roundtrips and minimizes the amount of data transferred on the network.

Query execution

But what happened on the server when a query is executed?
Every field has a function associated with it, and every time the server needs to produce that field then that function is executed. Those functions are named resolvers.
In this specific example, it is defined a custom resolver for “reservationList” that provides a list of reservations and a custom resolver for “hotelDetails” that provides the necessary details for each hotel. For all the others fields, a built-in resolver is used to produce a scalar value.
If you are interested in analyzing the entire source code for this example, with the complete resolvers definition, you can find a really nice javascript implementation on github :-).
The execution aspect of a GraphQL server is described here. Once again, GraphQL is not an implementation: it only defines aspect for servers to execute queries. Even if GraphQL is not a ready-to-use library, there are already several GraphQL implementations such as graphql.js, graphql-ruby, graphql-java, and so on.

Introspection

A really cool feature of a GraphQL service is the ability to introspect itself. Every GraphQL server has a special schema field at the query root named __\_\_schema__:
1
{
2
  __schema {
3
    ...
4
  }
5
}

Using that field, the service can expose the definition of every object and every field it can provide. This leads to really nice features like:

  • Auto documentation: the client knows the exact GraphQL schema.
  • Code generation: the client can use a client generated from the schema.
  • Static validation: the GraphQL client can validate the query before sending it to the server
As a consequence, there are available very useful tools like GraphiQL, that is a kind of schema explorer for GraphQL. It is really useful to try and discover server features.

HTTP Caching

We get a lot of advantages using GraphQL, but there are also drawbacks. The one I faced is HTTP caching.
A GraphQL endpoint can receive queries in different formats and it is really hard to define a caching policy server-side. Often the solution is to use a client-side cache. There are already libraries to implement normalized cache client-side, such as Apollo and Relay.
Even if caching on the client is a good solution in most cases, I believe this situation can be improved in the future.
For instance, a “smart” cache system can analyze a GraphQL request and understand which part of the query can take advantage of the cache.

Conclusion

Personally, I am quite happy in using GrapQL server-side and I tend to prefer it over REST. I think the most valuable advantage is the fact that clients already know how to query a GraphQL service and this makes integration straightforward.
Anyway, this article covers only a few GraphQL features. There are more such as mutations, subscriptions, deferred queries, live queries, and batch operations. Please refer to the official GraphQL website for further information.
A really useful resource is https://www.howtographql.com/ which contains free tutorials to learn all about GraphQL covering several GraphQL implementations.