A little over a month ago, Facebook flagged its GraphQL, which has been open source for over a year, as Production Ready (graphql.org/blog/produc…) Open, almost at the same time, making its early GraphQL API access (developer.github.com/early-acces…). . Does GraphQL, which has been around for more than five years and was born around the same time as Facebook’s News Feed, mean it’s going to take off as REST API in the coming days?
REST API
Let’s start with a simple example to illustrate the similarities and differences between REST and GraphQL. Suppose that TubiTV has an API to fetch a user from the system. In terms of the REST API, the interface would look something like this:
GET /v1/users/1
The result is then returned:
{ "first": "Tyr", "last": "Chen", "email": "..." , "bookmarks": [ "12345", "12346", "12347" ], "total_view_time": 10800 }Copy the code
Bookmarks is the user’s favorite movie. If the client calls this API to display the user’s profile, this API alone is not enough because Bookmarks does not expand and cannot render directly, so we will probably provide another API:
GET /v1/users/1/bookmarks
The return result is:
[ { "id": "12345", "title": "Doctor Strange", "description": "...", "poster": "//cdn.tubitv.com/12345.jpg", "url": "/ / cdn.tubitv.com/12345-1280x714-, 559141, 4223, 6264, 2362 8, k.m p4. M3u8"},...Copy the code
Such apis, while concise and each doing its job, are not client-friendly, requiring multiple requests to get all the data used for rendering. Especially for mobile clients, any extra requests can be a huge drag on the user experience. Therefore, such apis tend to compromise:
GET /v1/users/1/expand=bookmarks
From this, the API returns content containing bookmark details by providing additional parameters. This compromise can vary depending on the requirements, such as allowing the API to return partial fields:
GET /v1/users/1/fields=first,last,email,bookmarks(title,poster)expand=bookmarks
The variety of their own way “patch”, lack of overall concept, easy to influence each other, like Ptolemy’s geocentric theory model, everything is very good at first, with the development of the astronomical observation, this model have to add more round, catering to the observation data, finally overwhelmed the theory and replaced by the heliocentric theory.
In the above example, if the caller forgot to include bookmarks in the fields, expand does no work; Otherwise, fields containing bookmarks(title,poster) but no expand returns an error. The compromise between ideal and reality of REST apis can make other things difficult. The Swagger doc (or other doc, like RAML, jSON-schema) is just too cumbersome to write just because the User API supports both fields and expand. What? You never write a Doc like Swagger? So how do clients explore API capabilities?
Not to mention API versioning and obsolescence of older versions — there are always iOS/Android users who resist progress and would rather die than upgrade.
GraphQL API
GraphQL was born out of many real-world problems with REST. As an API query language, GraphQL wants the API to be flexible enough to handle complex and changing user scenarios from a product perspective. The above user API can be accessed as follows:
{ user(id: 1) {
first
last
email
bookmarks {
id
title
description
poster
url
}
total_view_time
}
}Copy the code
If a part of the product does not require access to Bookmarks, you can query it like this:
{ user(id: 1) {
first
last
email
total_view_time
}
}Copy the code
To achieve this goal, GraphQL defines a complete type system. The server informs the client of the server capability by defining the data type, so it is also a contract. The REST API architecture itself and its various frameworks do not define a proper type system, which leads to many fragmented, imperfect implementations, or implementations that rely on tools like Swagger. GraphQL also defines a rigorous query language. The REST API doesn’t make a lot of sense here, and basically the QUERyString/body API doesn’t have a lot of rules to follow, so you get along with it. As a result, GraphQL can easily generate powerful validation tools from the type system and user-defined schema to ensure that The Query is correct and meets the server capability.
Let’s look at sample code for the server that handles the above query:
The code above is easy to understand, so I won’t go into detail. Notably, a field of
resolve
The function returns a
Promise
So you can do a lot of interesting things, for example, here
total_view_time
A service from within. From this point of view, GraphQL handles heterogeneous data sources very well and concisely. It’s not that traditional REST apis can’t handle heterogeneous data sources, but that code can be less readable to write. From this perspective, GraphQL fits well as a thin layer of API gateway that acts as a bridge between clients and various internal systems, including REST apis.
As mentioned earlier, GraphQL clients have the flexibility to combine queries within the server’s capabilities, which is great for backward compatibility and versioning. REST apis tend to evolve with API versions, but the GraphQL API doesn’t have to. For the same API, the server only needs to add a new field, and the new client can use the new field when querying, without affecting the old client. It’s an elegant evolutionary scheme.
Having said a lot about GraphQL, here are some considerations for using GraphQL as an API.
Using GraphQL is not meant to make the API more efficient
GraphQL only defines the UI part of the API, and whether it is more efficient than REST API depends on how it is implemented. In fact, non-optimized GraphQL APIS generally perform worse than REST apis. Because GraphQL resolves individually for each field, it’s easy to have N+1 queries. Nodejs’ GraphQL implementation takes this into account and provides a way for Loader to allow more efficient queries. Therefore, use loader wisely in Resolve.
In addition, since GraphQL and Relay are mentioned at the same time in many cases, some people attach the ability of Relay to GraphQL, thinking that partial data loading is attributed to GraphQL, but in fact, it is not. In addition, using Relay can introduce complexity to both the client and the server, so it is not recommended to introduce Relay directly if you are just starting out with GraphQL. The food should be eaten in one bite.
GraphQL’s flexibility is a double-edged sword
Life is problems on top of problems, software architecture is tradeoff stacked tradeoff organized. The powerful and flexible query capabilities of GraphQL are eye-watering, but there are many security and performance implications. If the user has friends, the client can query:
{ user(id: 1) {
first
last
email
friends {
first
friends {
first
friends {
...
}
}
}
}
}Copy the code
Such queries are not possible in REST apis, but are reasonable queries in GraphQL, and without you writing any code, the querier will faithfully execute your resolve function over and over until the system runs out of memory or the stack runs out. So, although theoretically queries can be nested infinitely, real deployment requires specifying a nested upper limit and specifying a timeout for each API, beyond which the query is killed.
The old caching mechanism may fail
In the REST API world, we can cache the API at the load Balancer level using nginx cache or HA proxy — if the API is idempotent, the same input will get the same output, and therefore can be cached. After GraphQL is used, since queries are usually large, they are submitted in the form of POST. POST is not idempotent, so the original cache mechanism will be invalid. If your API’s performance is heavily dependent on load Balancer-level caching, pay special attention.
Using GraphQL can add complexity to the implementation
For a programmer, using GraphQL means she has to learn a new subject. Some simple CRUD apis become more complex with GraphQL.
GraphQL is now a mature technology, supported by almost all languages. If you’re going to use GraphQL, it’s important to control its flexibility and benchmark for performance. If you want to migrate an existing API system to GraphQL, you can initially wrap the existing REST API with GraphQL and let the client engineers experiment with it. Then rewrite the existing APIS one by one, depending on their importance and urgency. Don’t start with a complete rewrite.
Write a qualified REST API
Give me a Promise, and I’ll give you a Promise