The basic concept

GraphQL

GraphQL is a query language for apis. Developed and open source by Facebook, GraphQL is a server-side runtime that executes queries using a type based system (defined by your data). GraphQL isn’t tied to any particular database or storage engine, but relies on your existing code and data.

background

I believe that the above basic concept, we are as cute as I am. So here is the need to introduce its background and reasons.

In our current front and back end development, most of the interaction is done in the form of HTTP requests to the server interface. In this scenario, every time requirements change, a new interface needs to be modified or created to meet specific requirements.

For example, in an item detail page, when we need to retrieve item details, the server gives the front end an interface, for example:

https://www.example.com/getInfoById?infoId=000000

When the front end requests the interface, it returns data in a fixed format, such as:

{data: {title:'Title of Commodity',
        content:'Description of Goods',
        special:'Commodity Characteristics',
        price:'Commodity price',
        image:'Picture of merchandise'}}Copy the code

After receiving the data, the front end will conduct various corresponding processing and display, and finally display the page containing commodity title, commodity description, commodity characteristics, commodity price and commodity picture information to the user.

Everything looked great until one day…

Product swagger came over, lightly said: “can you remove the characteristics of the goods, add a commodity inventory, and also need to add a seller’s module to go in. It includes the seller’s name and profile picture, and you can click on the details page of the seller. You don’t have to worry too much, just go online before lunch.”

So before and after sitting together began to discuss, the front end of the weak said: “can you change your interface, the product do not have to remove, the product need to add”.

Back end heart said, you when I silly ah, and then hit the mouth while quickly said: “this change risk is too big, a lot of data are not a table, I can not check. In this way, the details page interface I do not change, you do not show not over, in case of which day the product boy boy again want to add, we also have to busy. Inventory gives you another interface, seller information gives you another interface, perfect, and that’s it.”

The front end still wants to say what, but the back end has gone farther and farther with the product.

Just when the front end was desperate, there was a thunderbolt and GraphQL came out.

In graphQL mode, assuming that the server part has been deployed and the front end uses the VUE framework, the request of the front end part can be simplified as follows:

  apollo: {
    goods: {
      query() {
        return gql`{
            goods(infoId:"${this.infoId}"){
              title
              content
              price
              image
          }
        }`
      }
    },
    store: {
      query() {
        return gql`{
            store(infoId:"${this.infoId}"){
              store
          }
        }`
      }
    },
    seller: {
      query() {
        return gql`{
            seller(infoId:"${this.infoId}"){
              name
              age
          }
        }`
      }
    }
  }

Copy the code

You can see that GraphQL defines an SQL-like query language for the API. Unlike the previous data request processing, in this case, we only need to define the data we need, no longer care about the rest of the data, we can demand the data we need. This provides greater freedom and convenience for our development. As long as data support, we can get rid of the dependence on server-side interface, improve production efficiency, win freedom and complete the front-end attack.

Front end practice

Having told the story, we moved on to the actual stuff. There has been a lot of practical experience for GraphQL on the Internet. The following part is a summary after referring to the practical experience and practicing myself.

The service side

The technical selection of the server side was completed by using eggJS framework and egg-GraphQLegg-GraphQL plug-in.

1. Install dependency packages
$ npm install --save egg-graphql
Copy the code
2. Enable the plug-in
// config/plugin.js
exports.graphql = {
  enable: true,
  package: 'egg-graphql'}; // enable cros to access exports.cors = {enable: true, 
    package: 'egg-cors'
}
Copy the code
3. Configure graphQL routing and cross-domain
/ / config/config. Default. Js / / graphql routing config graphql = {the router:'/graphql'// Whether to load to app, app is enabled by default:trueBy default, the agent is disabled:false// Whether to load the developer tool graphiQL. It is enabled by default. The same route as the Router field. Use a browser to open the visibility. graphiql:true// graphQL interceptor before routing onPreGraphQL:function*(CTX) {}, // Development tools graphiQL route before the interceptor, recommended to do permissions (such as only provide developers use) onPreGraphiQL:function*(CTX) {},} // cors cross-domain config.cors = {origin:The '*',    
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}
Copy the code
4. Start graphQL middleware
//config/config.default.js
exports.middleware = [ 'graphql' ];
Copy the code

The project configuration is in the section.

5. Write salesman code

So let’s start coding. The directory structure is as follows:

├─ ├─ General exercises, ├─ ├─ general exercises, └ │ ├─ general Exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises In addition can also custom │ │ | | ─ ─ scalars / / custom type definition │ │ | | └ ─ ─ the date. The js / / date type │ │ | └ ─ ─ resolver. Js / / merge all global type definition │ │ | └ ─ ─ Schema. Graphql / / schema definition │ │ └ ─ ─ goods / / commodity details graphql model │ │ └ ─ ─ the js / / connection data service │ │ └ ─ ─ resolver. Js / / type, │ │ ├ ─ ├ ─ ├.graphql // ├ ─ ├ ─ ├.graphql // Define product data object here │ │ └ ─ ─ store / / inventory model of graphql │ │ └ ─ ─ the js / / connection data service │ │ └ ─ ─ resolver. Js / / type │ │ └ ─ ─ Schema.graphql //schema definition, Define product data object here │ │ └ ─ ─ seller / / seller information graphql model │ │ └ ─ ─ the js / / connection data service │ │ └ ─ ─ resolver. Js / / type │ │ └ ─ ─ Schema. Graphql / / schema definition, define here goods details data object │ │ └ ─ ─ query / / all queries after here, Here is a general entrance │ │ └ ─ ─ schema. Graphql / / schema definition │ ├ ─ ─ service │ │ └ ─ ─ goods. Js / / commodity details of specific implementation │ │ └ ─ ─ store. Js / / inventory of specific business logic │ │ ├ ─ molecular.txt // ├ ─ molecular.txtCopy the code

App/graphql/query/schema. Graphql is the total of the whole graphql query entrance, all need to query object defined here. It is defined as follows:

# define the query object. Use # signs for comments in graphQL
type Query {
goods(
  The query condition is equivalent to the input commodity ID of the interfaceinfoId: ID! ) :Goods# Goods is working in the app/graphql/Goods/schema graphql defined in the product details
}
Copy the code

For all query objects involved in the general entry, corresponding folders need to be created under the GraphQL folder. For goods mentioned above, corresponding goods folder exists in app/ GraphQL folder. The Goods folder contains three sections: schema.graphql, resolve.js, and connector.js. Schema.graphql needs to define the Goods object mentioned in the general entry:

# goods
type Goods {
    # serial number
    infoId: ID!
    # Product titletitle:String! .# Product content
    content:'String! , # special:'String! .# Commodity price
    price:'nt! , # product image:'String!,
}
Copy the code

Graphql comes with a default set of scalar types, including Int, Float, String, Boolean, and ID. You need to specify the type when you define a field, which is one of the features of GraphQL that supports strong typing. If not empty, follow the type! Number. Graphql also includes enumerated types, lists, and custom types, as you can see in the documentation.

Resolve.js is a concrete implementation of the data type that relies on connector.js:

'use strict'
module.exports = {
  Query: {
        goods(root, {infoId}, ctx) {
        return ctx.connector.goods.fetchById(infoId)
  }
}
Copy the code

Connector.js is a concrete implementation of connecting data. Dataloader can be used to reduce data access frequency and improve performance:

'use strict'Dataloader = require(); // Dataloader = require();'dataloader')
class GoodsConnector {
    constructor(ctx) {  
        this.ctx = ctx  
        this.loader = new DataLoader(id=>this.fetch(id))
    }
    fetch(id) {  
        const goods = this.ctx.service.goods  
        return new Promise(function(resolve, reject) {const goodsInfo = goods.getInfobyId (id) resolve([goodsInfo])})} fetchById(id) {return this.loader.load(id)
    }
}
module.exports = GoodsConnector
Copy the code

This.ctx.service.goods is the exported method object of the goods.js file in app/service folder, which is the specific business logic to obtain the data:

const Service = require('egg').Service
const {createAPI} = require('.. /util/request'Class GoodsService extends Service {async getInfoById(infoId) {const result = await createAPI(this,'example/getInfoById'.'get', {infoId})
        return result
    }
}
module.exports = GoodsService

Copy the code

The data can be retrieved in any way you can, either directly from the database or using HTTP from an existing interface. This completes a GraphQL service implemented using the Egg framework. Let’s talk about the front end.

The front end

We will use VUE and Apollo to complete front-end construction.

Procedure 1 Install dependency packages
npm install --save vue-apollo apollo-client
Copy the code
2. References to Apollo
import 'isomorphic-unfetch'Apollo-client uses fetch directly. Import {ApolloClient} from is compatible with earlier versions of the browser'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'

Copy the code
3. Configure the link
Const httpLink = new httpLink ({// An absolute path URI is required:'http://exzample.com/graphql',})Copy the code
4. Create ApolloClient instances and providers
// Create the apollo client
const apolloClient = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache(),
  connectToDevTools: true,
})
const apolloProvider = new VueApollo({
  defaultClient: apolloClient,
})
Copy the code
4. Introduce it into VUE
Vue.use(VueApollo);
Copy the code
5. Root instance reference
    var vm = new Vue({
      el: '#app',
      provide: apolloProvider.provide(),
      router,
      components: {
        app: App
      },
      render: createEle => createEle('app')})Copy the code
6. Use
<script>
import gql from "graphql-tag"; 
export default { 
    data() { 
        return{goods: {}, infoId:123123}; }, apollo: { goods: {query() {
                return gql`{
                    goods(infoId:"${this.infoId}"){
                        title
                        content
                        price
                        image
                    }
                }`
            }
        },
     }
 }; 
 </script>
Copy the code

Looking forward to

Graphql provides a relatively perfect solution to the current problems such as large number of interfaces, difficult maintenance, high cost of expansion, unpredictable data format, and difficult document maintenance. I believe that in the future, it will be an indispensable part of our work.