30 minutes to understand the core concepts of graphql

Time:2020-5-20

Write in front

In the last article RPC vs rest vs graphql, we made a macro comparison of the advantages and disadvantages of the three. Moreover, we will find that generally simple projects do not need graphql, but we still need to have a certain understanding and mastery of the new technology, so we will not be caught off guard when the new technology is popularized.

This article mainly introduces some core concepts that I need to understand during my contact with graphql, which are more suitable for the following people:

  • Readers who have heard of graphql want to know more about it
  • Readers who want to learn graphql systematically
  • Readers investigating graphql Technology

These concepts are not limited to the server or the client. If you are familiar with these concepts, you can get started quickly through documents when you touch any library or framework using graphql as the technical background.

If you have applied graphql to the actual project, this article may not be suitable for you, because it does not contain some summary and experience in practice. I will write another article summary about the practice later.

What is graphql

This paper introduces what graphql is. It is a kind of query language at the core of the article. Furthermore, it is an API query language.

Some people here might say, what? Can API check? Isn’t the API used to call? Yes, that’s the power of graphql, quote from the official document:

ask exactly what you want.

When we use the rest interface, the data format and data type returned by the interface are pre-defined by the back-end. If the returned data format is not what the caller expects, we can solve the problem as the front-end through the following two ways:

  • Communicate with backend, change interface (change data source)
  • Do some adaptation work by yourself (processing data source)

In general, if it’s a personal project, you can change the back-end interface at will. But if it’s a company project, changing the back-end interface is often a more sensitive thing, especially when the three ends (web, Android, IOS) share the same set of back-end interfaces. In most cases, the problem is solved in the second way.

Therefore, if the return value of the interface can be changed from static to dynamic by some means, that is, the caller can declare what data the interface returns, which can further decouple the relationship between the front end and the back end to a large extent.

In graphql, we define aSchemaAnd make a statementTypeTo achieve the above effects, we need to know:

  • The abstraction of data model is described by type
  • The logic of interface data acquisition is described by schema

This may be more abstract. Let’s explain it one by one.

Type

The abstraction of data model is described by type. Each type consists of several fields, and each field points to a certain type.

There are two types of graphql, one is calledScalar type, another is calledObject type

Scalar Type

Built in scalar inclusion in graphql,StringIntFloatBooleanEnumThese should be well understood by people familiar with programming languages.

It is worth noting that in graphql, you can use theScalarDeclare a new scalar, such as:

  • PRISMA (a library that uses graphql to abstract database operations), andDateTimeandIDThese two scalars represent date format and primary key respectively
  • When using graphql to implement the file upload interface, you need to declare aUploadScalar to represent the file to be uploaded

In short, we just need to remember that scalar is the smallest particle in the graphql type system, and we will mention it again when graphql parses query results.

Object Type

Scalar alone is not enough to abstract some complex data models. At this time, we need to use object types. For example (ignore syntax first, only in the literal sense):

type Article {
  id: ID
  text: String
  isPublished: Boolean
}

The above code declares aArticleType, which has three fields, namelyIDID of type,StringText andBooleanType ispublished.

For field declaration of object type, we usually use scalar, but we can also use another object type, for example, if we declare a newUserType, as follows:

type User {
  id: ID
  name: String
}

Then we can change a little bit aboutArticleType, as follows:

type Article {
  id: ID
  text: String
  isPublished: Boolean
  author: User
}

ArticleNewauthorThe field of isUserType, representing the author of this article.

In summary, we use object model to build the shape of a data model in graphql, and at the same time, we can also declare the internal association among various models (one to many, one to one or many to many).

Type Modifier

There is another important concept about type, that is, type modifier. There are two types of type modifiers, namelyListandRequired , their syntax is[Type]andType!At the same time, the two can be combined with each other, such as[Type]!perhaps[Type!]perhaps[Type!]!(please look carefully here!Their meanings are as follows:

  • List itself is required, but its internal element can be empty
  • The list itself can be empty, but its internal element is required
  • List itself and internal elements are required

Let’s go a step further and change the above example if we declare a newCommentType, as follows:

type Comment {
  id: ID!
  desc: String,
  author: User!
}

You’ll find out hereIDThere is one!, which means that this field is required. Please update againArticleObjects, as follows:

type Article {
  id: ID!
  text: String
  isPublished: Boolean
  author: User!
  comments: [Comment!]
}

Our changes here are as follows:

  • ID field changed to required
  • Author field changed to required
  • Added comments field, whose type is a list type with element of comment type

FinalArticleType is a relatively simple type declaration about the article data model in graphql.

Schema

Now let’s introduceSchemaWe briefly described its function, that is, it is used to describeFor interface acquisition data logicHowever, this description is still abstract. In fact, we may as well regard it as that of each independent resource in the REST architectureuriTo understand it, only in graphql, we use query to describe how to get resources. Therefore, we canSchemaIt is understood as a table composed of multiple queries.

A new concept is involved hereQuery, used in graphqlQueryTo abstract the query logic of data, under the current standard, there are three query types, namelyQuery (query)Mutation (change)andSubscription

Note: for the convenience of distinction,QuerySpecifically, queries in graphql (including three types),queryRefers to the query type in graphql (query type only)

Query

The three basic query types mentioned above areRoot queryFor traditional crud projects, we only need the first two types. The third type is for the current increasing popularityreal-timeApplication.

We can understand them literally as follows:

  • Query: when obtaining data, the query type should be selected
  • Mutation: when attempting to modify data, the mutation type should be used
  • Subscription: when you want data to change, you can push messages, using the subscription type

It is still illustrated by an example.

First of all, we use rest and graphql toArticleFor the data model, write a series of crud interfaces, as follows:

Rest interface

GET /api/v1/articles/
GET /api/v1/article/:id/
POST /api/v1/article/
DELETE /api/v1/article/:id/
PATCH /api/v1/article/:id/

GraphQL Query

query {
  articles(): [Article!]!
  article(id: Int): Article!
}

mutation {
  createArticle(): Article!
  updateArticle(id: Int): Article!
  deleteArticle(id: Int): Article!
}

Compared with the rest interface we are familiar with, we can see that in graphql, query functions are divided according to the type of root query, and at the same time, the data types returned by each query are explicitly declared. The syntax about types here is the same as that in the previous chapter. It should be noted that anyQueryAll must beRoot QueryThis is related to the operation mechanism inside graphql.

In the example, we only declare the query type and the music type, if our application hasreal-timeIn rest, we may directly use long connection or provide some interfaces with verification to obtain long connection URL, such as:

POST /api/v1/messages/

After that, the long connection will push the new data to us. In graphql, we will declare it in a more declarative way, as follows

subscription {
  updatedArticle() {
    mutation
    node {
        comments: [Comment!]!
    }
  }
}

We don’t have to worry about the syntax here, because the purpose of this article is not to let you learn the syntax of graphql in 30 minutes, but to understand some of its core concepts. For example, here, we declare a subscription query, which will push new data objects when a new article is created or updated. Of course, in practice, its internal implementation is still based on long connection, but we can declare it in a more declarative way.

Resolver

If we only declare several queries in the schema, then we only do half of the work, because we do not provide the logic of the data returned by the relevant query. In order for graphql to work properly, we need to understand another core concept,Resolver (analytic function)

In graphql, we will have a convention that query and its corresponding resolver have the same name, so that they can be mapped in graphql. For example, aboutarticles(): [Article!]!This query, its resolver, must be calledarticles

Before introducing resolver, it’s time to understand the internal working mechanism of graphql as a whole. Let’s assume that now we are going to use thearticlesWe may write the following query statements (also ignore the syntax temporarily):

Query {
  articles {
       id
       author {
           name
       }
       comments {
      id
      desc
      author
    }
  }
}

When graphql parses this query statement, it will follow the steps below (simplified version):

  • First of all, the first level of analysis is carried outQueryOfRoot QueryThe type isquery, and its name is requiredarticles
  • You will try to use it laterarticlesOfResolverGet the parsing data. The first layer is finished parsing
  • After that, the return value of the first layer is parsed, and the second layer is parsedarticlesThere are also three childrenQuery, respectivelyidauthorandcomments

    • ID is scalar type in the author type, end of parsing
    • The author is the object type user in the author type, trying to use theUserOfResolverGet data, current field parsing completed
    • After that, the return value of the second layer is parsed, and the third layer is parsedauthorThere is also aQuery, name, because it is a scalar type, parsing ends
    • Comments as above

We can find that the general parsing process of graphql is to try to use its resolver value after encountering a query, and then parse the return value. This process is recursive until the type of the parsed field isScalar typeuntil. In the whole process of parsing, we can think of it as a long resolver chain.

Here, the parsing process of graphql is just a simple summary, and its internal operation mechanism is far more complex than this. Of course, these are black boxes for users, and we only need to know about its process.

The declaration of resolver itself is different in different languages because it represents the concrete logic of data acquisition. Its function signature (take JS as an example) is as follows:

function(parent, args, ctx, info) {
    ...
}

The meaning of the parameters is as follows:

  • Parent: return value of the current previous resolver
  • Args: pass in a query function (for example, in the above examplearticle(id: Int)Inid
  • CTX: intermediate variable continuously passed in resolver resolution chain (similar to context in middleware architecture)
  • Info: ast object of current query

It is worth noting that the resolver internal implementation is completely black box for graphql. This means that how resolver returns data, what kind of data to return, and where to return data from all depend on Resolver itself. Based on this, in practice, many people often use graphql as an intermediate layer. Data acquisition is encapsulated by resolver. The implementation of internal data acquisition may be based on RPC, rest, WS, SQL and other different ways. At the same time, based on this point, when you are migrating some systems that do not use graphql (such as rest), you can do a good incremental migration.

summary

About so many. First of all, thank you for reading this patiently. Although the topic is to be familiar with the core concepts of graphql in 30 minutes, it may have timed out, but I believe you are familiar with the core concepts of graphql. But it involves much more than this, and it is still in rapid development.

Finally, I try to provide some directions and suggestions for further study and understanding of graphql based on the experience of learning graphql in this period, for reference only:

To learn more about graphql itself

I suggest that you go to the official website carefully and read the official documents. If you are interested, it is also excellent to see the spec of graphql. Although this article introduces the core concepts, other concepts are not involved, such as union, interface, fragment, etc. these concepts are based on the core concepts, and should be easy to understand after understanding the core concepts.

Favor server

If you prefer the server side direction, you need to know more about the specific ecology of graphql in a certain language, as well as some specific directions such as caching, uploading files, etc. If you want to do system migration, you need to do some research on specific frameworks, such as graphene Django.

If you want to use graphql for system development, it is recommended to understand a framework called PRISMA. It is built on graphql, and has good compatibility with some graphql ecological frameworks. It is also adaptable to all major programming languages. It can be used as an ORM or as an intermediate layer for database interaction.

Client preference

If you prefer the client side, you need to know more about graphql client. What I have learned in this period is Apollo, an open-source grapql client framework, and it is compatible with various mainstream front-end technology stacks such as angular and react. It feels good to use.

At the same time, we need to understand some additional query concepts, such as connection, edge, etc. involved in paging query.

Probably so much. If there are any mistakes, please correct them.

Welcome to the official account.Full stack 101Only technology, not life
30 minutes to understand the core concepts of graphql

Recommended Today

NOR flash memory begins the development of automobile field

As cars become more intelligent and require more storage space, many technologies are struggling for the driver’s seat, but it is certain that the NOR flash can at least use a shot gun.With its programmable ability, nor flash exists in many applicationsEEPROMIt has found new opportunities in applications that require fast, nonvolatile memory, including communications, […]