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