What is GraphQL?

Official website definition:

A query language for apis

GraphQL was created for data communication. The client needs to tell the server what data is needed, and the server needs to satisfy the client’s data needs with the actual data. GraphQL is an intermediary for this communication.

Vernacular translation:

As long as the front end students clearly describe the data you need, send it to the server through HTTP, and the server will return you the data in response. Just as you write SQL statements to query the database.

Why use GraphQL?

A single entry

  • Rest API both front and back end need to do API management, version and path management, very troublesome.
  • (1) GraphQL has only one entry, which is equivalent to accessing a database. If we send it a query statement, it will return the specified result.

(2) We will obtain relevant information by viewing the schema and assemble effective query statements. (3) Version management can be achieved by changing the schema file, which is generally compatible with the old version and only adds the attribute fields required by the new version.

Data aggregation

In order to achieve the above interface display, we need the banner, brand and column information respectively. How to implement GraphQL and traditional REST API respectively?

  • GraphQL itself supports data aggregation, which is passed on request{ banner { .. } brand{ .. } column{ .. }}Such a description is given to the back end to get the desired data in the responder body.
  • REST API (1) The front end requests multiple interfaces to obtain data. (2) The back end encapsulates data according to the UI interface and provides an interface to return data.

According to the need to return

Many times, the same set of data is stored on different clients (Web, WAP, mobile……) In order to adapt to different terminals, the back end usually uses one interface to return all the information in a unified manner. As a result, some fields are not needed in the special client. This not only increases the network transmission time, response redundancy, and maintenance costs.

However, using GraphQL we can take whatever value we want, describe whatever we need, and get what we need.

Strongly typed

The GraphQL type system defines data types including Int, Float, String, Boolean, ID, Object, List, and non-NULL, and supports custom types. The GraphQL-schema-typescript library allows you to convert Schema files into typescript, so you can clearly know the type of each field when writing queries or responding to results. Avoid the problem of unclear field types when using response data.

The document

How to efficiently maintain a complete and detailed API documentation has always been a back-end headache. The GraphQL schema is just like your database table. You need to define and maintain annotations for each field. After GraphQL service is started, you can access the automatically generated document page by accessing/graphiQL, as shown below:

GraphQL basis

Let’s take a look at some of the important basics of GraphQL.

Schema

Before GraphQL development, the back-end service will provide all the data structure diagrams of the service, which we call schema. With this schema file, we can combine the queries or updates we need based on the data structures within the file.

The query process

Once you have a Schema, the client will combine queries based on the data structure in the Schema. What about the back-end processing of queries?

Figure 5 shows the GraphQL request to response process from 1 to 5.

  1. HTTP request body: Describes the data structure required by the front end (combined with information in the Schema file)
  2. When the request arrives at the server, the parser first parses user, the first layer under Query, where the processing logic for user can be written.
  3. The parser digs into the ID field under user to parse the ID field.
  4. The name field, level with id, is parsed by the parser.
  5. HTTP response body: Returns the result after processing.

From the processing process of the whole query, we can see that for each structure and each field required by the client, the backend students can process or return by default, increasing the playability. For example, when parsing the name field, the back end can determine whether to return all uppercase, all lowercase, or uppercase names. The client can obtain the required name format by passing corresponding parameters, which is very practical in time format, length format, and area unit.

Connect to the backend

To use GraphQL, we must push the backend students to develop with us. We can access the new project or partially transform the REST project.Part of a REST project can be transformed. For example, we can transform the user-related parts of an existing project. Nodejs is used here to demonstrate the code for other languagesGraphql-Code.

Step 1: Define the Schema file

Using User as the data model, the interface is converted into GraphQL Schema file from the REST perspective. REST interface:

GET /user: lists all users. POST /user: creates a user. GET /user/ID: obtains information about a specified user. Update information about a specified zoo (providing partial information about the user) DELETE /user/ID: Deletes a userCopy the code

Convert to GraphQL Query:

ID: ID, ID, ID, ID, ID, ID, ID, ID # name name: String! Not included in the REST interface is query {users():[User!] ! user(id: Int!) : User! } mutation { createUser(): User! updateUser(id: Int): User! deleteUser(id: Int): User! }Copy the code

Step 2: Resolver

Translate business or DAO operations within various REST project interfaces into GraphQL’s Resolver (parsing function). Combined with GraphQL base-query process implementation, the process of Resolver is the recursive traversal process of Query.

// 1. Define the schema type and resolver
const Unit = new GraphQLEnumType({
  name: 'Unit'.description: "Unit".values: {
    MM: {value: 'MM'},
    cm: {value: 'cm'},
    mm: {value: 'mm'}}})const User = new GraphQLObjectType({
  name: 'User'.description: "User information Entity".fields: () = > {
    return ({
      id: {type: new GraphQLNonNull(GraphQLInt)},
      name: {type: new GraphQLNonNull(GraphQLString)},
      // Resolve is processed before puberty
      stature: {
        type: GraphQLFloat,
        args: {
          unit: {type: Unit}
        },
        resolve: function (user, {unit}) {
          if (unit == 'MM') {
            return user.stature / 100;
          }
          if (unit == 'cm') {
            return user.stature;
          } else if (unit == 'mm') {
            return user.stature * 10; }}}}); }})// 2. Create a Schema
const Query = new GraphQLObjectType({
  name: 'UserQuery'.description: 'User Information Query'.fields: () = > ({
      user: {
        // The return type is User entity
        type: User,
        description: 'Query a user by ID'.args: {
          id: {type: new GraphQLNonNull(GraphQLInt)}
        },
        // Parse the user query
        resolve: async function (source, {id}) {
          Select * from user where id=?
          return (awaitutil.searchSql($sql.queryAll))[id]; }},users: {
        type: new GraphQLList(User),
        description: 'Query all user list'.// Parse functions for users queries
        resolve: async function () {
          SELECT * FROM 'user' WHERE 1=1
          return awaitutil.searchSql($sql.queryAll); }}}}))const schema = new GraphQLSchema({
  query: Query,
  / / omit mutation.. This is the same as query, but the SQL statement is changed
  mutation: Mutation
})

// enable service graphqlHTTP = require('express-graphql')
app.use('/graphql', graphqlHTTP({
    schema,
    / / enable GraphiQL
    graphiql: true 
}))
Copy the code

The Mock data

Front-end development access

Configure the front-end development environment

Maintaining Schema files

  1. Install graphQL-CLI to help us effectively manage schema files, endpoint information, static detection, etc.
  2. Create a new one in the root directory of the project.graphqlconfig.yamlFile, configure graphQL, configuration items reference:graphql-config
"SchemaPath ": "schema.graphql", // Check the included files by default. [" *. GQL "], "extensions" : {/ / back-end site "endpoints" : {/ / development environment "dev" : "http://localhost:3003/graphql", / / production environment "prod" : {}}}}}}Copy the code
  1. By executing in the root directorygraphql get-schemaNew | command can update the schema file.
  2. IDE supports Vscode to install VScode-graphQL, Webstorm can install jS-graphqL-intellij-plugin

Prompt & static check

Writing graphQL’s request query body without autoprompt or field detection is a very bad experience. It is easy to be inconsistent with the structure in the schema file, causing the query to fail. You can handle the fault in the following ways:

  1. Eslint introduces the graphQL rule eslint-plugin-graphQL, and the configuration looks like this:

     module.exports = {
       env: {
         browser: true.es6: true
       },
       parserOptions: {
         parser: 'babel-eslint'
       },
       // omit related items...
       rules: {
         / / to omit...
         'graphql/template-strings': [
           'error',
           {
             // Since I didn't use any Graphql framework client, I used graphqL-config, so I just wrote literal here
             Reference: / / https://github.com/apollographql/eslint-plugin-graphql#example-config-when-using-graphqlconfig
             env: 'literal'}},plugins: [
         'graphql']}Copy the code
  2. Eslint — ext.js — ext.gql — ext.graphQL

  3. Because of the configuration of includes in the.graphqlconfig.yaml file, editing the request body in the.gql and.graphQL files will automatically prompt you or report errors based on the structure of the schema file. Js-graphql-intellij-plugin (not limited to IntelliJ, GoLand, Pyu, Webstorm, etc.)

Then you can happily see the prompt and error:

Vue GraphQL – Plugin plug-in

Front-end JavaScript using GraphQL There are many frameworks available for graphQL-code-javascript. Most front-end libraries are friendly to new projects, but not friendly to front-end projects that use GraphQL partly and REST partly. Therefore, vue-GraphQL-plugin is developed to reduce the intrusion of front-end projects and better compatibility with old projects.

Quick access to the

Plug-ins are mixed into the VUE module through mixins

Install plug-in configuration items

Vue.use(VueGraphql, {
  // Request framework, can access any such as: axios, flyio, etc
  AjaxRequest: request,
  // The method in the request framework to handle GraphQL requests
  reqFunc: 'gQLRequest'.// Whether to enable debugging information
  debug: true
})
Copy the code
Configuration items mandatory type instructions
AjaxRequest true Object Request framework, can access any such as: Axios, Flyio, etc
reqFunc true String The name of the method in the request framework that handles the GraphQL request
debug false Boolean Whether to enable debugging information

Configure in the module

graphql: {
    ['Custom name'] : {// Each configuration item}}Copy the code

We only care about the configuration items, [‘ custom name ‘] will be used later when we call them manually.

Configuration items mandatory type instructions
query true Object The key in the object is the key that responds to the data assignment and is automatically set to the query statement in the data object and value is GraphQL
variables false Object Parameter variables corresponding to GraphQL query statements will be automatically set in data, and watch will be used for automatic query.

Note: The key under noWatch is not set under Watch.
isImmediate false Boolean Whether to execute immediately
debounce false Boolean | Object Whether to enable anti-shake function Use {wait: 1000} to enable the function
throttle false Boolean | Object Whether to enable throttling is enabled by {gapTime: 1000}
ajaxOptions.catchSuccess false function To get a successful callback to bind to the current module, you can happily use this

Compatible with REST style

This.$graphql.query({query, variables, ajaxOptions}) or this.$graphql.mutation({query, variables, ajaxOptions}) AjaxOptions}) to retrieve or update data.

Data and Components

Often queries or updates to the same data model are scattered across different sub-components, as shown in the following figure:

The figure above shows that there are different sub-components to query the user information, and the same code fragment can be passedgraphql-tagSeparate out different structure types for better organization and maintenance, similar to ORM (object-relational mapping).Please sendgraphql-tagImport the project and configure the GraphQL-tag /loader into webpack.

Related to the practice

Quick show

In actual projects, some pages need to load a large amount of data, resulting in a long request time and poor user experience. For example, the first screen rendering usually takes more HTTP round-trip time (RTT) because it requires more content to be requested on the first screen, resulting in a blank screen. If the blank screen lasts too long, the user experience will be significantly reduced. This problem is easily solved using GraphQL. For example, the data we need for our page is as follows:

User {id name age profile mobile avatar}Copy the code

In fact, on the first request we could have just taken the key information for a quick display of the interface

User {id name}Copy the code

In this way, after the user sees the interface first, we can request the rest of the information again and return to the application to solve the actual problem as needed.

Make efficient use of the Resolve resolution function

Taking advantage of the Resolve function’s ability to handle each field allows us to better define the type required for each field’s front end. For example, the user height information is displayed in centimeters in some interfaces, and meters in some interfaces. We can define length unit LengthUnit, and the back end performs the Resolve custom processing for length in User, and returns the corresponding unit format passed in by the front end, as shown in the figure below:

Various units of measurement (length, area, volume……) All defined, in the use of unified processing.

reference

  1. GraphQL official documentation
  2. Apollo GraphQL
  3. Vue Apollo
  4. GraphQL-Config