A few years ago, I led a development team at DocuSign that was tasked with rewriting a Web application used by tens of millions of users. There was no API to support the front end, because from the beginning, Web applications were one. NET large monomer. The API team in Seattle is breaking up and gradually exposing RESTful apis. The API team was made up of two engineers and had a one-month release cycle, while our front end team in San Francisco released new releases every week.
The API team’s release cycle is understandably too long, as many (almost all) features have to be manually tested. It’s a singleton, after all, and there’s no proper automated testing — if they change one place, there’s no telling what might go wrong elsewhere in the application.
I remember a time when our front-end team was under pressure to deliver a new release for a conference, but we forgot to follow up on an important API change that was not included in an upcoming RELEASE of the API. We either wait until the deadline is missed, or someone is willing to give up priority so that our changes can be included in upcoming releases. Fortunately, this change was eventually included in the new release, and we released the new front-end in time. I really wish we had used GraphQL at the time, because it eliminates the heavy reliance on external teams and their release cycles.
Many companies have internally moved from RESTful to GraphQL APIS: IBM, Twitter, Walmart Labs, The New York Times, Intuit, Coursera, and more.
Other companies have turned external apis into GraphQL not only internally but also: AWS, Yelp, GitHub, Facebook, Shopify, to name a few. GitHub is even going to stop using REST apis, with their V4 release using GraphQL only.
Is GraphQL a buzzword or a real revolution? Interestingly, most of the companies I’ve listed that have benefited from GraphQL have these things in common.
-
They have multiple clients, including mobile;
-
They are moving to or have already adopted a microservices architecture;
-
Their legacy REST apis have exploded in number and complexity;
-
They want to eliminate the dependency of the client team on the API team;
-
They focus on good API documentation and developer experience.
The GitHub engineering team stated their motivation:
“GraphQL Bridges the gap between what is published and what can be used. We’re really looking forward to releasing them all at the same time. GraphQL represents a huge leap forward in API development. Type safety, introspection, documentation generation, and predictable responses all benefit maintainers and consumers of our platform. We look forward to a new era of platforms powered by GraphQL and hope you do the same!”
GraphQL speeds up development, improves the developer experience, and provides better tools. I’m not saying that’s absolutely true, but I’ll do my best to illustrate the argument between GraphQL and REST and why.
I’m the head of software engineering at Indeed, so let’s take a look at the Indeed.com home page and job search results page first. They made 10 and 11 XHR requests, respectively.
Note that using POST for page browsing in REST is not very “formal.”
Here are some of the calls:
-
The GET:
https://inbox.indeed.com/api/getConversationCount
-
The GET:
https://www.indeed.com/rpc/jobdescs
-
The GET:
https://www.indeed.com/rpc/vjslog
-
The GET:
https://www.indeed.com/rpc/preccount
-
POST:
https://www.indeed.com/rpc/jobalert
-
POST:
https://www.indeed.com/rpc/count
When using GraphQL, the above requests can be contained in a single query and a single request.
query HomePage { getConversationCount(...) { ... } jobdescs(...) { ... } vjslog(...) { ... } preccount(...) { … } jobalert(...) { … } count(...) { … }}
Copy the code
The response might look something like this:
{ "data": { "getConversationCount": [ { ... } ], "vjslog": [...] , "preccount": [...] , "jobalert": [...] , "count": {} }, "errors": []}
Copy the code
In general, a single call is more convenient and efficient than multiple calls because it requires less code and less network overhead. The development experience from the PayPal process team also confirms that a lot of THE UI work is not actually UI work, but other tasks, such as communication between the front end and the back end:
“We found that UI developers actually spend less than a third of their time building the UI, with the rest of the time spent figuring out where and how to get data, filtering/mapping data, orchestrating API calls, and some more for building and deployment.”
It is important to note that it is also necessary to have multiple requests in real time, for example, multiple individual requests that can quickly and asynchronously fetch different data independently, they increase deployment flexibility if the microservices architecture is adopted, and they have multiple points of failure instead of one.
In addition, if the page is being developed by multiple teams, GraphQL provides the ability to decompose the query into fragments. We’ll talk more about this later.
From a larger perspective, the GraphQL API’s main application scenario is the API gateway, which provides an abstraction layer between the client and the service.
The microservices architecture is great, but there are some issues that GraphQL can address. Here are some lessons from IBM’s use of GraphQL in microservices architecture:
“Overall, the GraphQL microservice was very fast to develop and deploy. They started development in May and went into production in July. Because they don’t have to ask permission, they just do it. He strongly recommended it. It was much better than a meeting.”
Let’s take a look at each of the benefits of GraphQL one by one.
First, GraphQL helps reduce the number of requests made. It is much easier to get the data you need through a single call than through multiple requests. From an engineer’s point of view, this speeds up development. I’ll explain more about why this is happening later, but for now I want to address another issue.
The back-end and client teams need to work closely together to define apis, test them, and make changes. Front-end, mobile, Internet of Things (Alexa, for example) client teams are constantly iterating on features and experimenting with new UX and designs. Their data needs are constantly changing, and the back-end team must keep up with them. If the client and back-end code were the same team, the problem would be less severe. Most of Indeed’s engineering team is made up of full-stack engineers, but not all of them. For non-full-stack teams, the client team is often slowed down by relying on the back-end team.
When I moved to the Job Seeker API team, the mobile team started our development schedule. We had a lot to communicate about parameters, response fields, and testing.
With GraphQL, the client engineers have complete control of the front end and don’t need to rely on anyone else because they can tell the back end what they need and what the response structure should be. They use GraphQL queries that tell the back-end API what data to provide.
Client engineers don’t have to spend time with the back-end API team to add or modify something. GraphQL is self-documenting, so you can save some time looking up documents to learn how to use the API. I’m sure most people have wasted a lot of time trying to figure out the exact request parameters. The GraphQL protocol itself and its community provide some useful tools for documentation. In some cases, documents can be generated automatically from the schema. Other times, simply using the GraphiQL Web interface is enough to write a query.
Engineers from the New York Times said they didn’t need to change much when making changes after switching to GraphQL and Relay:
“When we want to update the design of all products, we no longer have to modify multiple code bases. That’s what we want. We see Relay and GraphQL as the perfect tools to help us achieve this great goal.”
When a company already has a lot of GraphQL APIS, and someone comes up with a new product idea, this is my favorite scenario for GraphQL. Prototyping using the existing GraphQL API is much faster than calling various REST endpoints (which will provide too little or too much data) or building a new REST API for a new application.
The speed of development is closely related to the development experience.
GraphQL provides a better developer experience (DX), and developers will spend less time thinking about how to get data. With Apollo, they just had to declare the data in the UI. Data and UI together make it easier to read and write code.
Typically, UI development involves jumping between UI templates, client code, and UI styles. GraphQL allows engineers to develop the UI on the client side, reducing friction because engineers don’t have to switch between files when adding or modifying code. If you’re familiar with React, here’s a good analogy: GraphQL is to data what React is to UI.
Here is a simple example where the property names launch.name and launch.rocke.name are directly included in the UI.
const GET_LAUNCHES = gql` query launchList($after: String) { launches(after: $after) { launches { id name isBooked rocket { id name } } } }`; export default function Launches() { return ( <Query query={GET_LAUNCHES}> {({ data, loading, error }) => { if (loading) return <Loading />; if (error) return <p>ERROR</p>; return ( <div> {data.launches.launches.map(launch => ( <div key={launch.id} >{launch.name}<br/> Rocket: {launch.rocket.name} </div> ))} </div> ); }} </Query> ); };
Copy the code
Using this approach, it is very easy to modify or add new fields to the UI or query (GQL). React components are much more portable because they describe all the data needed.
As mentioned earlier, GraphQL provides better documentation, and there is also an IDE called GraphiQL:
Front-end engineers love GraphiQL. Here’s a quote from a senior engineer at Indeed:
“I think the best part of the development experience is being able to use GraphiQL. For me, this is a more efficient aid to writing queries than typical API documentation.
Another great feature of GraphQL is fragmentation, because it allows us to reuse queries at a higher component level.
These features improve the developer experience, making developers happier and less prone to JavaScript fatigue.
Engineers aren’t the only ones who benefit from GraphQL. The user also benefits because the application’s performance is improved (perceived) :
-
Reduced payload (the client only needs what is necessary);
-
Combining multiple requests into one request can reduce network overhead.
-
Client-side caching and back-end batch and back-end caching are easier to implement using tools;
-
Prefetch.
-
Faster UI updates.
PayPal redesigned their checkout process using GraphQL. Here’s the feedback from users:
“REST principles do not take into account the needs of Web and mobile applications and their users, and this is particularly evident in checkout optimization transactions. Users want to be invoicing as quickly as possible, and if the application uses a lot of atomic REST apis, there will be multiple round trips between the client and server to get data. Our checkout takes at least 700 milliseconds per round-trip, not including the time the server takes to process the request. Every round trip results in slow rendering, poor user experience, and lower settlement conversion rates.”
Among the performance improvements is “multiple requests grouped into one request to reduce network overhead.” This is very true for HTTP/1, which does not have the same multiplexing mechanism as HTTP/2. But while the multiplexing mechanism provided by HTTP/2 helps optimize individual requests, it does not actually help with graph traversal (retrieving related or nested objects). Let’s take a look at how REST and GraphQL handle nested objects and other complex requests.
Often, clients make complex requests to get ordered, sorted, filtered data or subsets (for paging), or to request nested objects. GraphQL supports nested data and other queries that are difficult to implement using standard REST API resources (also called endpoints or routes).
For example, let’s say we have three resources: users, subscriptions, and resumes. The engineer needs to make two separate calls in sequence (which degrades performance) to retrieve a user’s resume, first to retrieve the user resource through the call, then to retrieve the resume ID, and then to retrieve the resume data using the resume ID. The same is true for subscriptions.
1.GET/Users /123: The response contains a list of resume ids and job notification subscriptions;
2.GET /resumes/ABC: The response contains resume text — depends on the first request.
3.GET/SUBSCRIPTIONS /XYZ: The response contains the content and address of the job notice — dependent on the first request.
The example above is bad for a number of reasons: the client might get too much data and have to wait for the related request to complete before proceeding. In addition, the client needs to implement how to get sub-resources (such as build or subscribe) and filter.
Imagine that one client might only need the content and address of the first subscription and the current position in the resume, while another might need all the subscriptions and the entire resume list. So, if you use the REST API, it’s a little uneconomical for the first client.
Another example: a user table might contain the user’s first and last name, email, resume, address, phone number, Social Security number, password (obfuscated, of course), and other private information. Not every client needs all the fields, and some applications may only need user email, so sending information such as a Social Security number to these applications is not secure.
Of course, it is not feasible to create different endpoints for each client, such as/API /v1/users and/API /v1/usersMobile.
In fact, various clients often have different data requirements: / API /v1/userPublic, / API /v1/userByName, / API /v1/usersForAdmin, and if so, endpoints can grow exponentially.
GraphQL allows customers to ask the API to send the fields they want, which makes the back-end work much easier: / API/GQL — all clients only need this endpoint.
Note: For both REST and GraphQL, the back end needs to use access control levels.
Or you can use old REST to implement much of GraphQL’s functionality. But at what cost? The back end can support complex RESTful requests so that clients can make calls using fields and nested objects:
GET /users/? fields=name,address&include=resumes,subscriptions
Copy the code
The above request would be better than using multiple REST requests, but it is not standardized, not supported by client libraries, and such code is harder to write and maintain. For relatively complex apis, engineers need to use their own query string parameter conventions in queries to end up with something like GraphQL. Since GraphQL already provides standards and libraries, why design your own query convention based on REST?
Contrast this complex REST endpoint with the following GraphQL nested query, which uses more filtering criteria such as “Just give me the first X objects” and “sort by time in ascending order” (unlimited filtering options can be added) :
{ user (id: 123) { id firstName lastName address { city country zip } resumes (first: 1, orderBy: time_ASC) { text title blob time } subscriptions(first: 10) { what where time } }}}
Copy the code
With GraphQL, we can keep nested objects in our queries, and for each object, we’ll get exactly the data we need, no more, no less.
The data format of the response message reflects the structure of the requested query as follows:
{ "data": { "user": { "id": 123, "firstName": "Azat", "lastName": "Mardan", "address": { "city": "San Francisco", "country": "US", "zip": "94105" }, "resumes" [ { "text": "some text here...", "title": "My Resume", "blob" : "< blob >", "time" : "you T21:2018-11-13. 000 z"},], "subscriptions" :, "errors" : [] []}}
Copy the code
Another benefit of using GraphQL over complex REST endpoints is increased security. This is because urls are often logged, and RESTful GET endpoints rely on query strings that are part of the URL. This can expose sensitive data, so RESTful GET requests are less secure than GraphQL’S POST requests. I bet that’s why the Indeed home page uses POST to make a “read” page request.
Using GraphQL makes it easier to implement key features such as paging, thanks to standards provided by queries and BaaS providers, as well as standards used by back-end implementations and client libraries.
GraphQL’s schema is language-independent. Extending the previous example, we can define the Address type in schema:
type Address { city: String! country: String! zip: Int}
Copy the code
String and Int are scalar types! Indicates that the field cannot be empty.
Schema validation is part of the GraphQL specification, so queries like this will return an error because name and phone are not fields of the Address object:
{ user (id: 123) { address { name phone } }}
Copy the code
We can use our types to build complex GraphQL Schemas. For example, a user type might use our address, resume, and subscription type, as follows:
type User { id: ID! firstName: String! lastName: String! address: Address! resumes: [Resume] subscriptions: [Subscription]}
Copy the code
Many of Indeed’s objects and types are defined using ProtoBuf. Typed data is nothing new, and the benefits of typed data are well known. The advantage of GraphQL over inventing a new JSON type standard is that there are already libraries that can swap ProtoBuf to GraphQL automatically. Even if one of the library (rejoiner:https://github.com/google/rejoiner) can’t use, also can develop their own translator.
GraphQL offers greater security than JSON RESTful apis for two main reasons: strong schema types (such as data validation and no SQL injection) and the ability to define exactly what the client needs (without inadvertently leaking data).
Static validation is another advantage that saves engineers time and gives them confidence when refactoring. Such as eslint plugin – graphql (https://github.com/apollographql/eslint-plugin-graphql) tool can let the engineers know the backend changes, and let the back-end engineer to ensure that does not destroy the client code.
It is important to maintain the contract between the front end and the back end. When using the REST API, we need to be careful not to break the client code because the client has no control over the response message. Instead, GraphQL provides control for the client, and GraphQL can be updated frequently without major changes due to the introduction of new types. Because of its use of Schema, GraphQL is a versionless API.
When choosing a platform to implement the GraphQL API, Node is a candidate because GraphQL was originally used for Web applications and front ends, and Node is preferred for Developing Web applications because it is based on JavaScript. GraphQL is very easy to implement using Node (assuming a schema is provided). In fact, using Express or Koa only takes a few lines of code:
const Koa = require('koa'); const Router = require('koa-router'); // [email protected] graphqlHTTP = require('koa-graphql'); const app = new Koa(); const router = new Router(); router.all('/graphql', graphqlHTTP({ schema: schema, graphiql: true})); app.use(router.routes()).use(router.allowedMethods());
Copy the code
Schema is defined using types in NPM’s GraphQL. Query and Mutation are special schema types.
Most of the implementation of the GraphQL API is in the Schema and parser. Parsers can contain arbitrary code, but the most common are the following five main categories:
-
Call Thrift, gRPC, or other RPC services;
-
Calling the HTTP REST API (when overriding an existing REST API is not a priority);
-
Call the data store directly;
-
Call other GraphQL Schema queries or services;
-
Call the external API.
Here’s an example:
https://medium.freecodecamp.org/graphql-zero-to-production-a7c4f786a57b.
Node is great, but in Indeed, we mostly use Java. GraphQL is supported in many languages, including Java, for example:
-
https://github.com/graphql-go
-
https://github.com/graphql-python
Because Indeed mainly USES Java, so here is a Java graphql use graphql – Java example, the complete code at https://github.com/howtographql/graphql-java. It defines the/graphQL endpoint:
import com.coxautodev.graphql.tools.SchemaParser; import javax.servlet.annotation.WebServlet; import graphql.servlet.SimpleGraphQLServlet; @WebServlet(urlPatterns = "/graphql")public class GraphQLEndpoint extends SimpleGraphQLServlet { public GraphQLEndpoint() { super(SchemaParser.newParser() .file("schema.graphqls") //parse the schema file created earlier .build() .makeExecutableSchema()); }}
Copy the code
GraphQL’s schema is defined using POJOs. The GraphQL endpoint class uses the LinkRepository POJO. The parser contains the actual code for the operation (such as fetching links) :
@WebServlet(urlPatterns = "/graphql")public class GraphQLEndpoint extends SimpleGraphQLServlet { public GraphQLEndpoint() { super(buildSchema()); } private static GraphQLSchema buildSchema() { LinkRepository linkRepository = new LinkRepository(); return SchemaParser.newParser() .file("schema.graphqls") .resolvers(new Query(linkRepository)) .build() .makeExecutableSchema(); }}
Copy the code
In many cases, GraphQL’s schema can be automatically generated from other types of schemas, such as gRPC, Boxcar, ProtoBuf, or ORM/ODM.
GraphQL doesn’t necessarily require a client. A simple GraphQL request is a regular POST HTTP request that contains the query content. We can use any HTTP proxy library (CURL, AXIos, FETCH, SuperAgent, etc.) to generate the request. Using curl to send a request
curl \ -X POST \ -H "Content-Type: application/json" \ --data '{ "query": "{ posts { title } }" }' \ https://1jzxrj179.lp.gql.zone/graphql
Copy the code
The following code can run in any modern browser (to avoid CORS, visit launchpad.graphql.com).
fetch('https://1jzxrj179.lp.gql.zone/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: '{ posts { title } }' }),}) .then(res => res.json()) .then(res => console.log(res.data));
Copy the code
While it’s easy to build GraphQL requests, there are many other things you need to implement, such as caching, because caching can greatly improve the user experience. Building client-side caches isn’t that easy, but thankfully, Apollo and Relay Modern, among others, offer client-side caches out of the box.
Of course, there is no perfect solution (although GraphQL is close to perfect), and there are a few issues to be aware of, such as:
-
Does it have a single point of failure?
-
Is it extensible?
-
Who is using GraphQL?
Finally, here are our own top reasons why GraphQL might not be a good choice:
-
When the client requirements are simple: if your API is simple, such as /users/resumes/123, then GraphQL is a bit heavy.
-
Asynchronous resource loading is used to speed up the loading speed.
-
Use new apis when developing new products, rather than building on existing ones;
-
There are no plans to expose the API to the public;
-
No UI or other client changes are required;
-
Inactive product development;
-
Some other JSON Schema or serialization formats are used.
GraphQL is a protocol and a query language. The GraphQL API has direct access to the data store, but for the most part, it’s a data aggregator and an abstraction layer, a layer that speeds up development, reduces maintenance, and makes developers happier. Therefore, GraphQL makes more sense than a public API. Many companies are starting to adopt GraphQL. IBM, PayPal, and GitHub claim great success with GraphQL. If GraphQL is promising, can we now stop building outdated and clunky REST apis and embrace GraphQL?
English text: https://webapplog.com/graphql/
Front-end learning should not blindly pursue the learning framework, but should focus on the ability to solve problems and ideas, and accumulate more knowledge from the basic aspects. @Yubo, @Youyuxi, @Xiangma and other big VS are recommending “Relearning the Front End” to help you reorganize the front end structure and become a front end person who is “able to learn”.
New offer only ¥68, original price ¥99. After ordering, invite friends to buy, and get ¥24 cash back.