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.