⬆️ ⬇️

Rest in peace, REST. Long life GraphQL


Transfer. Original Samer Buna. Original article .


When I first learned about GraphQL after a long use of various REST APIs, I could not resist tweets with this content:

Rest API has become a REST-in-Peace API. Long life GraphQL



Translator's Note - Rest In Peace, RIP - a common epitaph "Rest in Peace". The first word in it is written in the same way as the acronym REST.

Then it was an attempt to make laugh, but now I am convinced of the justice of the playful forecast.



Understand correctly. I'm not going to blame GraphQL for killing REST or something. REST will never die, just as XML will live forever. But who in their right mind would use XML instead of JSON? In my opinion, GraphQL will do the same thing for REST as JSON has done for XML.



This article is not one hundred percent agitation in favor of GraphQL. For its flexibility you have to pay. This is a separate section.



I am an admirer of the approach. Start with the question WHY , why do so.



In short: Why GraphQL?



Here are the three most important issues GraphQL solves:





The article details how GraphQL solves these problems.



Let's start with a simple description for those who are not familiar with GraphQL.



What is GraphQL?



GraphQL is a language . If you teach him an application, it will be able to declare the necessary backend information about the necessary data, which GraphQL also understands.



As a child learns the language in childhood, and growing up is forced to put more effort into learning, so GraphQL is much easier to integrate into a newly created application than to integrate into a streamlined service.



In order for the service to understand GraphQL, you need to create a separate level in the query processing stack and open access to it for customers who need to interact with the service. This level can be considered a translator of the GraphQL language, or a GraphQL-understanding mediator. GraphQL is not a data storage platform. Therefore, it is not enough for us to simply understand the GraphQL syntax; we also need to translate queries into data.



The GraphQL level, written in any programming language, contains a scheme ( schema ) similar to a graph or a communication diagram, from which customers will learn about the capabilities of the service. Client applications familiar with GraphQL can make queries on this scheme in accordance with their own capabilities. This approach separates clients from the server and allows them to evolve and scale independently.



Queries in the GraphQL language can be either data queries - query (read operation), or mutations - mutation (write operations). In both cases, the query is a regular string, which the GraphQL service parses, executes, and maps to the data in a specific format. The common response format for mobile and web applications is JSON.



What is GraphQL? (explanation on fingers)



GraphQL does not go beyond data sharing. There is a client and server to interact with. The client should inform the server what data is needed, and the server should close this need with actual data. GraphQL is in the middle of an interaction.



image



Screenshot from my Pluralsight training course - Building Scalable APIs with GraphQL



You ask why the client can not communicate with the server directly? Of course it can.



There are several reasons to use the GraphQL level between clients and servers. Perhaps the most popular reason is efficiency . Typically, the client receives many resources on the server, but the server gives one resource at a time. Therefore, the client is forced to repeatedly contact the server to obtain all the necessary data.



GraphQL shifts the complexity of multiple queries to server shoulders, let GraphQL do it. The client sends a single request to the GraphQL level and receives a single answer, which contains everything that the client needs.



There are many other advantages of GraphQL. For example, an important advantage when interacting with multiple services. When many clients request data from many services, the GraphQL level in the middle simplifies and standardizes the exchange of data.



image



Screenshot from my Pluralsight training course - Building Scalable APIs with GraphQL



Instead of directly accessing the two services (on the previous slide), the client interacts with the GraphQL level, and that one already receives data from the services. In this way, GraphQL eliminates the need for a client to support different APIs by converting a single client request into requests to several data providers in a language they can understand.



Imagine three people speaking three different languages, and each has some information. If you need to ask a question that requires combining the knowledge of all people, the help of a translator who speaks all three languages ​​will greatly simplify the receipt of the answer. This is exactly what GraphQL does.



But computers are not yet so smart as to answer arbitrary questions on their own, and there must be algorithms somewhere. That is why, at the GraphQL level, it is necessary to define a schema, which customers can use.



The outline is basically a capability document that lists all the questions that a client can address at the GraphQL level. The scheme can be used quite flexibly, since it is a graph of nodes. In essence, the scheme limits what can be queried at the GraphQL level.



Not quite clear? Let's take a look at GraphQL, as a replacement for the REST API, which it actually is. Let me answer the question that you are probably asking now.



What is wrong with the REST API?



The big problem with the REST API is the large number of endpoints. This forces customers to make many requests to get the right data.



REST API is a set of destination points, each of which corresponds to a resource. If a client needs different resources, it is necessary to make several requests to collect all the necessary data.



REST API does not offer the client a query language. The client does not affect what data the server returns. There is simply no language in which the client could indicate this. More precisely, the means available to the client to influence the server are very limited.



For example, a destination for a READ operation allows you to do one of two things:





The client cannot specify, for example, which fields of the record he wants to take from this resource. This information is protected in the REST service itself, and it will always return all the provided fields, regardless of which of them are needed by the client. In GraphQL, this problem is called over-fetching information that is not required. Overloading in vain loads the network and consumes memory on the client and server side.



Another significant REST API problem is versioning. The need to support multiple versions means new destinations. This entails additional difficulties in the use and support of the API and may cause duplication of code on the server.



GraphQL is designed to solve these problems. Of course, these are not all the problems of the REST API, but I don’t want to delve into what the REST API is or is not. Rather, talking about the conventional resource-oriented approach to the API based on HTTP destination points. Over time, each such API turns into a jumble of ordinary destinations, as prescribed by REST, and special ones added for performance reasons. And here the alternative in the form of GraphQL looks much better.



What is behind GraphQL magic?



GraphQL is based on different ideas and architectural solutions, but perhaps the most important are the following:





Thanks to the last point, I personally believe in the excellence of GraphQL.



These are all high-level concepts. Consider a little more.



To solve the problem of multiple queries, GraphQL turns the server into a single destination. In fact, GraphQL absolutizes the idea of ​​a custom destination and makes the entire server a point that can respond to any request.



Another important idea is the presence of a developed query language due to which the client can work with a single destination. Without such a language, there would be no point in limiting the number of destinations. A language is needed to describe custom queries and return data.



Clients manage the interaction using the query language. They request what they need, and the server returns exactly what is requested. This solves the problem of data reloading.



GraphQL versioning is interesting. Versioning can be completely abandoned. In fact, you can add fields without deleting existing ones, because the data is a graph, and you can add nodes to it as you like. Therefore, you can leave paths for old APIs and enter new ones without marking their version numbers. Just the API has grown up.



This is especially true for mobile clients, since it is impossible to directly tell them which version of the API to use. The installed mobile application can use the old version of the API for many years. There is no problem for the web, as you can simply replace the code of the web application on the server. But it is much more difficult for mobile applications.



Still not convinced? What if we compare GraphQL and REST with a specific example?



RESTful API vs. GraphQL API - Example



For example, an interface is being developed on the theme of the Star Wars film and its characters.



The first thing to create is a simple visual component to display information about a single Star Wars character. Take Darth Vader, who appears regularly throughout the film. The component will show the name, date of birth, the name of the planet and the names of all films in which the character participates.



It sounds easy, but we are dealing with three different resources: Person, Planet and Film. They are simply interconnected, so that anyone can guess the data structure. The Person object belongs to the planet and owns from one to several Film objects.



The data for the first component looks like this:



 { "data": { "person": { "name": "Darth Vader", "birthYear": "41.9BBY", "planet": { "name": "Tatooine" }, "films": [ { "title": "A New Hope" }, { "title": "The Empire Strikes Back" }, { "title": "Return of the Jedi" }, { "title": "Revenge of the Sith" } ] } } } 


Let it come from the server just such a structure. Then you can visualize the data in React as follows:



 // The Container Component: <PersonProfile person={data.person} ></PersonProfile> // The PersonProfile Component: Name: {person.name} Birth Year: {person.birthYear} Planet: {person.planet.name} Films: {person.films.map(film => film.title)} 


This is a simple example, and since we are probably assisted by knowledge of Star Wars, the connection between the UI and the data is obvious. The UI uses all the keys we created from JSON.



Let's see how to get this data through the RESTful API.



First we get information about the character by ID. The RESTful API is expected to provide it like this:



 GET - /people/{id} 


Such a request will return the name, date of birth and other information about the character. A good RESTful API will also report the character's planet ID and the ID of all movies with it.



The JSON response might look like this:



 { "name": "Darth Vader", "birthYear": "41.9BBY", "planetId": 1 "filmIds": [1, 2, 3, 6], *** other information we do not need *** } 


Then we get the name of the planet:



 GET - /planets/1 


And then we get the names of the films:



 GET - /films/1 GET - /films/2 GET - /films/3 GET - /films/6 


And only after six requests we can collect the answers and provide the component with the necessary data.



In addition to the six queries to visualize a fairly simple component, this decision was imperative. We have specified how to receive and process data so that it can be passed to the component.



You can try it yourself and see what I mean. Star Wars has a RESTful API at http://swapi.co/ . Construct a character data object. The keys may be called a little differently, but the resource URLs will be the same. You need exactly six requests. Moreover, you will get redundant information that is not needed for the component.



Of course, this is one possible implementation of the RESTful API for this data. You can imagine the implementation better, which simplifies the task. For example, if the nested resources are available in the API and the server knows about the relationship between the character and the films, you can get movies like this:



 GET - /people/{id}/films 


But a simple RESTful API probably does not have this capability, and you will have to ask backend developers to create additional destination points for us. This is the practice of scaling RESTful API - you have to add all the new destination points to meet the needs of customers. Maintaining these points is quite time consuming.



Now take a look at the GraphQL approach. GraphQL server to the maximum embodies the idea of ​​a custom destination, bringing the idea to the absolute. There is only one destination on the server, and the way to communicate with it is not important. If you use HTTP, the HTTP request method will be ignored. Suppose there is a GraphQL destination point available on / graphql over HTTP.



Since the task is to get all the data at once, we need a way to specify the composition of the data to the server. To do this, use the GraphQL query:



 GET or POST - /graphql?query={...} 


A GraphQL query is simply a string containing all the necessary data. And here comes the power of declarativeness.



In Russian, the need for data is expressed as follows: for the specified character, the name, date of birth, name of the planet and the names of all his films are needed . In GraphQL, it looks like this:



 { person(ID: ...) { name, birthYear, planet { name }, films { title } } } 


Compare how the need for data in human language and GraphQL is described. The descriptions are as close as possible. Also compare the GraphQL query and the JSON that we started with. The request exactly repeats the structure of the expected JSON, not including the values. If we draw a parallel between the request and the response, the request is a response without data.



If the answer is:



     – . 


That question can be represented by the same expression, but without a specific meaning:



 ()    ? 


The GraphQL query has the same similarity. If you take the resulting JSON, remove all the "answers" (values), then we get a GraphQL query, suitable for the role of the question about this JSON.



Now compare the GraphQL query with the declarative React UI code, which describes the data. Everything that is specified in the GraphQL query is used in the UI, and everything used in the UI is present in the query.



This is a great way to represent the GraphQL data model. The interface knows what data is needed, and getting it is not difficult. Designing a GraphQL query is a simple task of identifying what is used as variables directly in the UI.



If you swap parts of this model, it will also be useful. On request, GraphQL makes it easy to imagine how the response is used in the UI, since the response has the same “structure” as the query. You do not need to specifically study the answer to understand how to use it, and you don’t even need API documentation. Everything within the request.



Star Wars has a GraphQL API at . Try using it to get data about the character. There are minor differences, but in general the request to obtain the necessary data in this API looks like this (with Darth Vader as an example):



 { person(personID: 4) { name, birthYear, homeworld { name }, filmConnection { films { title } } } } 


The query returns a structure very close to the needs of the visual component. But most importantly, all data is received at once.



GraphQL flexibility fee



The perfect solution is a myth. Along with the flexibility of GraphQL come some problems and concerns.



One of the threats with which GraphQL is open is network attacks on resource exhaustion (such as Denial of Service). GraphQL server can be attacked by excessively complex queries that consume all resources. Easily request data with deep nesting (user -> friends -> friends of friends ...) or use field synonyms to force the server to receive the same data many times. Although such attacks do not occur only in GraphQL, you need to keep them in mind when working with GraphQL.



There are several oppositions. You can analyze the cost of each request before executing and impose restrictions on the amount of data that the request can consume. You can enter a timeout for interrupting a request that is too long. Also, since GraphQL is only a level that associates a query with data stores, you can set constraints at deeper levels under GraphQL.



GraphQL API ( ), . , . , Facebook .



GraphQL – . – , GraphQL?



, , GraphQL DSL (domain specific language – ) . , ( ).



. GraphQL . . GraphQL, GraphQL , . RESTful API.



GraphQL . RESTful API , . . .



GraphQL . . , .



. Graph Query Graph Cache . , GraphQL: , – , .



. , . , . . . Relay.js « ».



, GraphQL – N+1 SQL-. GraphQL , . , SQL- .



RESTful API , N+1, SQL-. GraphQL, , . , Facebook – DataLoader .



, DataLoader , GraphQL. DataLoader . , SQL- .



DataLoader . , DataLoader . .



...



Thanks for attention. - Pluralsight Lynda . – Advanced React.js , Advanced Node.js Learning Full-stack JavaScript .



- - JavaScript, Node.js, React.js GraphQL . , (.). , ( ) #questions.



Samer Buna



')

Source: https://habr.com/ru/post/334182/



All Articles