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
+--------------------------------------+ +----------------------------+ +---------------------+ |
| 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:
- the keyword “schema”, that is the root of the schema;
- ID, String, and Int are built-in Scalar Types;
- ReservationStatus is an Enumeration Type;
- the others are Object Types.
Query example
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 | } |
Query execution
Introspection
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