前言:首先要明白的是GraphQL是用來幹嗎的也就是是解決什麼問題的,其實就是解決傳輸數據的可定製化,減小後端api的開發量。舉個例子:好比你獲取一個用戶列表,後端開發了一個叫getUserList接口,參數是parentId,返回的數據結構是這樣的:[ { name, id , logo , address } ]
,後來又有個業務只要數據結構是這樣的就能夠了:[ { name} ]
,這個時候要麼後端從新開發一個接口,要麼就是直接用getUserList,可是形成了數據浪費和網絡傳輸成本浪費,爲了解決這個問題GraphQL就被Facebook創造了出來,即能複用getUserList也不形成各類浪費。node
後端(使用的是nodejs,express)
一、安裝依賴:npm install express-graphql -S ; npm install graphql -S ; 二、單獨個目錄作route接口,index.js統一導出,方便之後代碼膨脹進行分塊,如圖
三、開始寫具體的業務代碼,拿個人base-graphql.js舉例ios
// 也能夠在不使用 GraphQL Schema Language 的狀況下實現相同的 API: const { graphqlHTTP } = require('express-graphql'); const graphql = require('graphql'); const { createBaseDb, createUserDb } = require('../utils/db-util'); //建立db對象 const DBBase = createBaseDb(); // 定義 數據庫對應的User類型 const UserType = new graphql.GraphQLObjectType({ name: 'User', fields: { id: { type: graphql.GraphQLInt }, version: { type: graphql.GraphQLInt }, create_date: { type: graphql.GraphQLString }, update_date: { type: graphql.GraphQLString }, update_user: { type: graphql.GraphQLInt }, name: { type: graphql.GraphQLString }, email: { type: graphql.GraphQLString }, server: { type: graphql.GraphQLString }, username: { type: graphql.GraphQLString }, password: { type: graphql.GraphQLString }, } }); const UsersType = new graphql.GraphQLList(UserType); // 定義查詢對象類型,對應post查詢傳參: query:{user(id:"a"){id,name,age},hello(name:"charming")} const QueryType = new graphql.GraphQLObjectType({ name: 'Query', fields: { queryUser: { description: 'query user', //resolve返回的數據類型 type: UserType, // `args` 描述了 `user` 查詢接受的參數 args: { id: { type: graphql.GraphQLString, } }, resolve(parentValue, args, request) { //查一個表的全部數據 let data = new Promise((resolve, reject) => { DBBase.all("select * from user", (err, res) => { if (err) { reject(err) } else { resolve(res[0]) } }) }); return data; } }, queryUsers: { description: 'query users', //resolve返回的數據類型 type: UsersType, // `args` 描述了 `user` 查詢接受的參數 args: { id: { type: graphql.GraphQLString, } }, resolve(parentValue, args, request) { //查一個表的全部數據 let data = new Promise((resolve, reject) => { DBBase.all("select * from user", (err, res) => { if (err) { reject(err) } else { resolve(res) } }) }); return data; } }, //能夠定義多個 hello: { description: 'a hello world demo', type: graphql.GraphQLString, args: { name: { // 這裏定義參數,包括參數類型和默認值 type: graphql.GraphQLString, defaultValue: 'Brian' } }, resolve(parentValue, args, request) { // 這裏演示如何獲取參數,以及處理 return 'hello world ' + args.name + '!'; } } } }); // ====================================下面時修改數據================================= // 輸入參數類型 const UserInputType = new graphql.GraphQLInputObjectType({ name: 'UserInput', fields: () => ({ name: { type: graphql.GraphQLString }, email: { type: graphql.GraphQLString }, username: { type: graphql.GraphQLString }, password: { type: graphql.GraphQLString }, }) }); const MutationType = new graphql.GraphQLObjectType({ name: 'Mutation', fields: { addUser: { //參數樣式 mutation {addUser(one:{id:"s",name:"alice",age:12,male:false}){id,name,age}} type: graphql.GraphQLString, // `args` 描述了 `user` 查詢接受的參數 args: { one: { type: UserInputType } }, resolve(parentValue, args, request) { let sqlStr = `insert into user (create_date,version,name,email,username,password) values ( '${new Date().toISOString()}', 0, '${args.one.name}', '${args.one.email}', '${args.one.username}', '${args.one.password}' )`; return new Promise((resolve, reject) => { DBBase.run('BEGIN TRANSACTION;'); DBBase.run(sqlStr, async (err, res) => { console.log("insert user ", err, res); if (err) { DBBase.run("ROLLBACK;"); reject(err) } else { //添加成功後,建立對應的用戶數據庫 try { await createUserDb(args.one.email); DBBase.run('COMMIT TRANSACTION;'); resolve(res) } catch (error) { console.log(error); DBBase.run("ROLLBACK;"); reject(err) } } }); }); } }, } }); const schema = new graphql.GraphQLSchema({ query: QueryType, mutation: MutationType }); module.exports = graphqlHTTP({ schema: schema, graphiql: true /* true表明須要調試 */ })
上面註釋寫的也比較清楚,簡單說下, 這裏它提供了GraphQLObjectType來定義對象數據類型的描述,若是是數組必須使用GraphQLList再進行構建,而後你就能夠用你構建的來聲明你要返回的類型,可是參數類型不能使用這個,必須是GraphQLInputObjectType這種input相關的來構建。 還有resolve方法裏是須要你直接return結果的,db的操做其實都是異步的,因此須要你用promise來解決 這個問題,當你的業務涉及事務等比較多db操做是async/await可能更方便,其餘的用法就看官方文檔吧,這裏就不展開了。sql
例子中 我按功能來劃分了模塊,我綜合思考了,仍是以爲這樣的普適性和開發難度是最好,對於一些複雜的大型項目確定仍是須要進行調整的。 好了到這裏,你就能夠直接用postman看看效果了 記得參數那裏不要是form-data,必定選的是GraphQL(這個我猜測就是form-data等這種現有的形式來作這個可能有點彆扭,因此乾脆另外定了一個格式),查詢參數相似這樣:query {queryUsers(id:"a"){id,name,email}}
,修改參數相似這樣:mutation {addUser(one:{name:"jack",email:"jack@qq.com",username:"jack",password:"123456"})}
;不用postman也能夠用自帶的,直接訪問https://localhost:3001就能夠了 。 寫到這裏你可能會想到現有的相似axios這種的框架不能用了,對的,必需要換成apollo-client這種支持的。因此若是是成熟項目要替換成GraphQL仍是須要成本的。數據庫