In the last six months, some of LeetCode’s new features have been experimenting with GraphQL. If you check the developer tools in LeetCode website collected in the request, may find a different request POST at https://leetcode.com/graphql/. Yes, if you want to write some crawlers for LeetCode, you might want to take a good look at what data we’re mounting under this Endpoint.

I went through a process of understanding, misunderstanding, and re-understanding while using GraphQL. As someone who has eaten GraphQL, I hope this article will help you understand what GraphQL is, what it gives you, and what you need to pay attention to when applying GraphQL to your system. This is not a systematic popular science article, if you have any other questions please leave them in the comments.

The following content is the author’s personal understanding, if wrong, welcome to point out. I’ll fix it at any time. Thanks!

1. What is GraphQL?

Officially, GraphQL is a query language for apis; In my opinion, GraphQL is a standard, and the opposite of a standard is implementation. Just like EcmaScript and JavaScript, you need to understand from the start that GraphQL only defines the syntax of the query language, how specific statements are executed, and so on. However, when you actually use a server-side implementation of GraphQL, it is possible to find that features described in the GraphQL standard have not been implemented. Or this implementation of GraphQL extends what the GraphQL standard defines.

For example, the ES 2017 standard officially includes async/await. From an implementation point of view, IE does not implement this standard, while Edge 16 and Chrome 62 implement this standard (data from Caniuse). In contrast, there are quite a few server-side implementations. Most of them follow the GraphQL standard, but there may be some differences, so you need to find out for yourself.

2. How to start GraphQL from zero?

  1. Standard: http://graphql.org/ (pure GraphQL, with nothing to do with JavaScript or Python)
  2. Look at the server implementation: go to http://graphql.org/code/ to find the implementation relevant to your server technology
  3. Look at the client implementation: Relay or appollo-client, etc.
  4. Learn to use DataLoader to get list data

3. What’s the difference between GraphQL and RESTful?

Let’s start with an image from Graphql.org. REST and GraphQL are both the external service interfaces of the system carried by the server, so they can definitely coexist and even share a set of business logic such as Authorization.

So what exactly distinguishes GraphQL from RESTful? I think there are two main points.

1. Entry Point

The core concept of RESTful is resource, and a RESTful interface only operates a single resource. So when you use RESTful, you design a lot of interfaces. GraphQL is a single portal, usually configured in [host]/ GraphQL /, from which all resources are retrieved or modified by GraphQL statements.

2. Relevance of data

RESTful operations operate on relatively discrete resources; GraphQL’s data is more holistic.

For example, if you want to get friends of A’s friends, what do you do with RESTful?

Suppose we have an interface like this:

GET /user/:userId/friends/Copy the code

Whereas A has 20 good friends, we need to send 20 + 1 = 21 REST requests in total.

Or we could design the following interface for this particular scenario:

GET /user/:userId/friendsAndHisFriends/Copy the code

Emmmmm… It may seem awkward, but it only takes one request!

So in GraphQL, how do you do that?

First we need to define the User Schema (GraphQL has a complete type system) :

type User {
  id: ID!
  name: String!
  friends: [User]
}Copy the code

Suppose we suspend only one Node on Graph root called user:

type Query { user(id: ID!) : User }Copy the code

The query we send from the client would look like this:

query ($userId: ID) {
  user(id: $userId) {
    name
    friends {
      name
      friends {
        name
      }
    }
  }
}Copy the code

This last request solves the need to query a friend of a friend. You’ve already figured it out: Can this query go on forever? You’re right, you can do it! The GraphQL website describes itself as follows:

It’s Graphs All the Way Down *

It’s like a tree that goes down forever. So in my opinion, GraphQL should be called TreeQL. Of course, in Graph theory, Tree is a Graph. Note that this also leads to the “N + 1 problem” — naive GraphQL server implementations make this query very slow!

How to solve this intractable problem? Impatient friends please jump to 6.1 N+1 problem!

4. Can GraphQL modify data?

Looking at the query example above, you must be wondering if GraphQL, which seems to exist only for queries, has any way to modify data.

The answer is: yes.

In order to complete the GraphQL data platform, an operator called mutation was added to the GraphQL standard. Because I think this kind of design is really more general, I will not give examples here, see graphql.org/learn/queri…

5. What are the advantages of GraphQL over RESTful?

1. Better correlation and structure of data

This is already described in question 3 of this article.

2. Easier front-end cache data

Relay and Apollo-Client do this for you. If you want to know how it works, please go to GraphQL Caching

3. Versionless API

In GraphQL, if you want the server to behave differently than it did before, you just change the root Query definition and add nodes on top of it, as opposed to RESTful version numbers that are compatible with old and new clients.

4. More robust interfaces

No more destabilizing time bombs for the system by modifying interfaces without communication. All front-end oriented interfaces are guaranteed by a strongly typed Schema, and the complete type definition is completely visible to the front end. Once the query sent by the front end is inconsistent with the Schema, errors can be quickly detected.

5. Long-awaited Subscription

How to receive server push messages in the browser is a perennial problem. From the initial polling, to the later WebSocket. Today GraphQL also plans to introduce subscription, a third operator besides Query and mutation, to accept server-pushed data directly. At the end of 2015 GraphQL published an official blog post: Subscriptions in GraphQL and Relay to introduce subscription to their iOS and Android apps. Unfortunately, the relevant code is still not open source. At present, the only solution that the open source community can find is graphqL-Subscriptions written by Apollo community for Node.js.

6. What are the drawbacks of GraphQL?

With all the benefits of GraphQL, are there any downsides? Of course there is.

6.1. The N + 1 problem

The biggest problem is that when implementing the GraphQL server-side interface, it’s easy to write extremely inefficient code that causes the “N+1 problem.”

What is the N+1 problem? Let’s start with a simple example:

def get:
    users = User.objects.all()
    for user in users:
        print(user.score)Copy the code

This is a simple python code that uses Django’s QuerySet to fetch data from a database. Suppose we have two tables in our database, User and UserScore. The relationship between the two tables is as follows:

Because the User’s score is not stored in the User table, and because QuerySet has lazy load, the for loop checks the User’s score once every time it obtains the User. The result is a problem that could be solved by a single database query. However, N+1 accesses to the database are generated in the improper implementation.

N+1 problems are more likely to occur in GraphQL than RESTful. This is mainly due to the layer-by-layer parsing of GraphQL Query. See GraphQL Execution for more details on how GraphQL executes a query.

6.2. How to solve the N + 1 problem in GraphQL?

The following solutions are for relational databases only, and may be quite different if you use NoSQL in your project.

  1. For one-to-one relationships (such as the relationship between User and UserScore I mentioned above), when fetching data from the database, join the required data into a table. Don’t wait for the ORM framework to load the data you need.
  2. For many-to-one or many-to-many relationships, you’ll need a library called DataLoader. Among other things, Facebook provides DataLoader implementations for the Node.js community. The main function of DataLoader is batching & Caching, which can combine multiple database query requests into one, and the loaded data can be directly retrieved from the DataLoader cache space. A new article would be necessary if the topic were to be discussed, but I won’t go into it here.

7. What are some fun ways to debug the GraphQL interface?

GraphiQL / live demo

It’s easy to feel the joy of “code as documentation” with GraphiQL.

8. How to choose the client implementation of GraphQL?

Common frameworks for clients are Relay and Apollo Client. Relay is an official solution provided by Facebook, while Apollo is the most popular community for GraphQL.

The advantage of using Relay is that many GraphQL server-side frameworks support Relay standards (such as data paging interfaces). The Apollo-client implementation, however, claims to be compatible with Relay in many ways, so it should be much the same. Of course, the author has not actually used Relay, and his experience in GraphQL is not profound enough, so it is not good to make an assertion.

When making the technology selection, Ashish said he was worried about Relay being too heavy, so he didn’t decide to use Relay. The correctness of this choice remains to be seen, and apollo-Client is currently being used in LeetCode’s actual projects.

9. How does GraphQL handle pagination?

This is a question that might worry GraphQL beginners, and one that can be answered in the official documentation.

Using another example of finding friends, the paging interface can be designed as follows:

query ($userId: ID) {
  user(id: $userId) {
    name
    friends(first: 2, offset: 3) {
      name
    }
  }
}Copy the code

The above example means taking the first two friends starting with the fourth friend of $userId.

Similarly, the paging interface can also be designed as

  • friends(first: 2, after: $friendId);
  • friends(first: 2, after: $friendCursor)

No matter how the paging interface is designed, it requires common encapsulation and support on both the front and back ends. Relay style paging interface has been completely implemented in each front-end and back-end GraphQL framework.

9.1 Relay style paging interface

  • See Relay Cursor Connections Specification
  • Note: Apollo-client is compatible with this paging interface
query {
  user {
    name
    friends(first: 2, after: $cursor) {
      edges {
        cursor
        node {
          id
          name
        }
      }
      pageInfo {
        hasNextPage
      }
    }
  }
}Copy the code

How to implement user verification in GraphQL?

Authentication belongs to the business logic layer, so don’t let GraphQL do too much work.

GraphQL Authentication

summary

In view of the limited GraphQL data in Chinese on the Internet, this paper is summarized according to the author’s own understanding. These ten questions are probably the ones I was concerned about when I started GraphQL, and may not be completely applicable to everyone. The official GraphQL documentation is an important resource if you want to have a deeper understanding of these issues. This post is just a tip for the community to share more about GraphQL gestures.

In addition, our recruitment in LeetCode Shanghai will be fully launched after the Spring Festival, welcome to send your resume. leetcodechina.com/jobs/

reference

  • GraphQL Specification
  • Async functions – caniuse
  • Learn GraphQL
  • GraphQL and Relay analysis
  • Subscriptions in GraphQL and Relay
  • Relay Cursor Connections Specification