GraphQL-Sword and Bridge for Front-end Development

Links to the original text: https://www.cnblogs.com/zhuanzhuanfe/p/10324700.html

Basic concepts

GraphQL

GraphQL is a query language for the API, developed by Facebook and open source, and runs on the server side using a type-based system to perform queries (the type system is defined by your data). GraphQL is not bound to any particular database or storage engine, but relies on your existing code and data support.

Background introduction

Believe that after reading the basic concepts above, we are all like me. So here we need to introduce the background and reasons of its emergence.

In our current front-end and back-end development process, most of the interaction process is completed by http request server interface. In this scenario, whenever requirements change, a new interface needs to be modified or created to meet specific requirements.

Take a chestnut:
In a product details page, when we need to get the product details, the server will give the front end an interface, such as:

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

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

{
    data:{
        title:'Title of Commodity',
        content:'Descriptive Contents of Commodities',
        special:'Commodity characteristics',
        price:'commodity price',
        image:'Pictures of merchandise'
    }
}

The front end receives the data, carries on various corresponding processing display, finally will contain the commodity title, the commodity description, the commodity characteristic, the commodity price, the commodity picture information page display to the user.

Everything looks good until one day...

The product swaggered over and said lightly, "Can we get rid of the characteristics of the goods, add a stock of the goods, and add a seller's module to it?" Containing the name and avatar of the seller, you can click on the details page of the seller, and don't worry too much. Just go online before lunch.

So the front and back end sit together and start to discuss, the front end weak said: "Can you change your interface, remove all products do not need, add all products needed?"

The back end said in his heart, you think I'm silly, so while smashing his mouth, he said quickly: "This is too risky to change, many data are not in one table, I can't check. In this way, I will not change the interface of the details page. If you don't show it, it will be over. If the kid of the product recalls it one day, we will have to work hard. Inventory gives you another interface, seller information gives you another interface, perfect, that's settled.

The front end wants to say something more, but the back end has gone farther and farther along with the product.

When the front end was desperate, the thunderbolt sounded loud and graphql came on the stage.

In graphql mode, assuming that our service end 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
          }
        }`
      }
    }
  }

You can see that graphql defines a sql-like query language for us, which is used for api. Unlike previous data request processing, here we only need to define the data we need, and the rest are no longer concerned, we can request the data we need on demand. This provides greater freedom and convenience for our development, as long as data support, we can get rid of the dependence on the server interface, improve production efficiency, win freedom, complete the front-end counter-attack.

Front-end and back-end practices

After telling the story, we began to talk about some practical dry goods.
For graphql, there are many practical experiences on the internet. The following part is a summary after referring to the practical experience and self-practice.

Server

We use the eggjs framework to select the technology of the server, and cooperate with the egg-graphqlegg-graphql plug-in.

1. Install dependency packages

$ npm install --save egg-graphql

2. Open plug-ins

// config/plugin.js
exports.graphql = {
  enable: true,
  package: 'egg-graphql',
}; 
//Open cros Cross-Domain Access
exports.cors = { 
    enable: true, 
    package: 'egg-cors'
}

3. Configuring graphql routing and cross-domain

//config/config.default.js
// graphql routing
config.graphql = {
router: '/graphql',
// Whether to load on app, open by default
app: true,
// Whether to load on agent or not, turn off by default
agent: false,
// Whether to load the developer tool graphiql and turn it on by default. Routing is the same as the router field. Use the browser to open the visibility.
graphiql: true,
// Interceptor before graphQL routing
onPreGraphQL: function*(ctx) {},
// Development tool graphiQL interceptor before routing, recommended for permission operations (such as only for developers)
onPreGraphiQL: function*(ctx) {},
}
// cors cross-domain
config.cors = {    
    origin: '*',    
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}

4. Open graphql Middleware

//config/config.default.js
exports.middleware = [ 'graphql' ];

The project configuration is reported in the paragraph.

5. Writing salesman code

Let's start coding.
The catalogue structure is as follows:

├── app
│   ├── graphql                          //The graphql code, all the graphql-related code is here, and it's already configured
│   │    └── common                   //General Type Definition, graphql has its own system type, besides, it can also be customized
│   │     |    |── scalars                 //Custom Type Definition
│   │     |    |  └──  date.js            // Date type implementation
│   │     |   └── resolver.js            //Merge all global type definitions
│   │     |   └── schema.graphql     // schema definition
│   │    └──goods                       // graphql model of commodity details
│   │         └── connector.js         //Connecting Data Services
│   │         └── resolver.js            //Type implementation, which corresponds to the model defined by schema.graphql in goods, is its concrete implementation
│   │         └── schema.graphql    //schema definition, where commodity details data objects are defined
│   │    └──store                        // graphql model of inventory
│   │         └── connector.js         //Connecting Data Services
│   │         └── resolver.js            //Type implementation
│   │         └── schema.graphql    //schema definition, where commodity details data objects are defined
│   │    └──seller                       // graphql model of seller information
│   │         └── connector.js         //Connecting Data Services
│   │         └── resolver.js            //Type implementation
│   │         └── schema.graphql    //schema definition, where commodity details data objects are defined
│   │    └──query                       // All queries pass through here. Here is a general entry.
│   │         └── schema.graphql    //schema definition
│   ├── service
│   │   └── goods.js                    //Specific Realization of Commodity Details
│   │   └── store.js                     //Specific business logic of inventory
│   │   └── seller.js                     //The Specific Business Logic of Seller Information
│   └── router.js

app/graphql/query/schema.graphql is the total entry point for the entire graphql query, where all objects that need to be queried are defined. Its definition is as follows:

#Define the query object, in graphql The use of comments in#Number
type Query {
goods(
  #Query condition, equivalent to the input commodity id of the interface
  infoId: ID!
):Goods #Goods is the product details defined in app/graphql/goods/schema.graphql
}

The query objects involved in the general entry need to establish corresponding folders under the graphql folder. For example, goods mentioned above, there are corresponding goods folders in the app/graphql folder. The goods folder consists of three parts: schema.graphql, resolve.js, and connector.js.
The Goods object mentioned in the general entry needs to be defined in schema.graphql:

# commodity
type Goods {
    # Pipeline number
    infoId: ID!
    # Commodity Title
    title:String!,
    # Commodity content
    content:'String!,
    #Commodity characteristics
    special:'String!,
    #commodity price
    price:'nt!,
    #Merchandise Pictures
    image:'String!,
}

Graphql comes with a set of default scalar types, including Int, Float, String, Boolean, ID. The need to specify types when defining fields is also one of the characteristics of graphql, which supports strong types. If it's not empty, follow the type with a! Number. Graphql also includes enumeration types, lists, and custom types, which allow you to view relevant documents.

Resolution.js is a concrete implementation of data types, which depends on connector.js:

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

connector.js is a concrete implementation of connecting data. Data loader can be used to reduce the frequency of data access and improve performance:

'use strict'
//The introduction of dataloader, launched by facebook, can significantly reduce the frequency of database access, often used in Graphql scenarios
const 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])  //Note that you need to return to array form here
        })
    }
    fetchById(id) {  
        return this.loader.load(id)
    }
}
module.exports = GoodsConnector

this.ctx.service.goods involved in the above code is the method object exported from goods.js file under the app/service folder, that is, the specific business logic for obtaining data:

const Service = require('egg').Service
const {createAPI} = require('../util/request')//Implemented http requests
class GoodsService extends Service {
// Access to commodity details
    async getInfoById(infoId) {
        const result = await createAPI(this, 'example/getInfoById', 'get', {infoId})
        return result
    }
}
module.exports = GoodsService

Data can be obtained in any way you can, directly from the database, or from existing interfaces using http.
Such a graphql service implemented with egg framework is completed.
Let's talk about the front end.

Front end

We will use vue and Apollo to build the front end.

1 Installation Dependency Package

npm install --save vue-apollo apollo-client

2. Reference to apollo

import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'

3. Configuration links

const httpLink = new HttpLink({
  // You need to configure an absolute path
  uri: 'http://exzample.com/graphql',
})

4. Create ApolloClient instances and PROVIDER

// Create the apollo client
const apolloClient = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache(),
  connectToDevTools: true,
})
const apolloProvider = new VueApollo({
  defaultClient: apolloClient,
})

4. Introduce use in vue

Vue.use(VueApollo);

5. Root instance reference

    var vm = new Vue({
      el: '#app',
      provide: apolloProvider.provide(),
      router,
      components: {
        app: App
      },
      render: createEle => createEle('app')
    })

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>

expectation

Graphql provides a relatively perfect solution to the problems of large number of interfaces, difficult maintenance, high cost of expansion, unpredictable data format and difficult maintenance of documents. It is believed that graphql will be an indispensable part of our work in the future.

Welcome to Technical Public: Architect Growth Camp

Keywords: Vue Database npm SQL

Added by pipeten on Mon, 02 Sep 2019 15:26:26 +0300