本文將從GraphQL是什么伟众,為什么要使用GraphQL理张,使用GraphQL創(chuàng)建簡單例子赫蛇,以及GraphQL實戰(zhàn),四個方面對GraphQL進(jìn)行闡述雾叭。說得不對的地方悟耘,希望大家指出斧正。
github項目地址:https://github.com/Charming2015/graphql-todolist
一织狐、GraphQL是什么?
關(guān)于GraphQL是什么暂幼,網(wǎng)上一搜一大堆筏勒。根據(jù)官網(wǎng)的解釋就是一種用于 API 的查詢語言。
一看到用于API的查詢語言旺嬉,我也是一臉懵逼的管行。博主你在開玩笑吧?你的翻譯水平不過關(guān)邪媳?API還能查嗎捐顷?API不是后端寫好,前端調(diào)用的嗎雨效?
的確可以套菜,這就是GraphQL強(qiáng)大的地方。
引用官方文檔的一句話:
ask exactly what you want.
二、為什么要使用GraphQL?
在實際工作中往往會有這種情景出現(xiàn):比如說我需要展示一個游戲名的列表,可接口卻會把游戲的詳細(xì)玩法夫啊,更新時間遮晚,創(chuàng)建者等各種各樣的 (無用的) 信息都一同返回。
問了后端渣蜗,原因大概如下:
原來是為了兼容PC端和移動端用同一套接口
或者在整個頁面屠尊,這里需要顯示游戲的標(biāo)題,可是別的地方需要顯示游戲玩法啊耕拷,避免多次請求我就全部返回咯
或者是因為有時候項目經(jīng)理想要顯示“標(biāo)題+更新時間”讼昆,有時候想要點擊標(biāo)題展開游戲玩法等等需求,所以把游戲相關(guān)的信息都一同返回
簡單說就是:
* 兼容多平臺導(dǎo)致字段冗余
* 一個頁面需要多次調(diào)用 API 聚合數(shù)據(jù)
* 需求經(jīng)常改動導(dǎo)致接口很難為單一接口精簡邏輯
有同學(xué)可能會說那也不一定要用GraphQL啊骚烧,比方說第一個問題浸赫,不同平臺不同接口不就好了嘛
http://api.xxx.com/web/getGameInfo/:gameID
http://api.xxx.com/app/getGameInfo/:gameID
http://api.xxx.com/mobile/getGameInfo/:gameID
或者加個參數(shù)也行
http://api.xxx.com/getGameInfo/:gameID?platfrom=web
這樣處理的確可以解決問題,但是無疑加大了后端的處理邏輯赃绊。你真的不怕后端程序員打你既峡?
這個時候我們會想,接口能不能不寫死碧查,把靜態(tài)變成動態(tài)运敢?
回答是可以的,這就是GraphQL所做的!
三忠售、GraphQL嘗嘗鮮——(GraphQL簡單例子)
下面是用GraphQL.js和express-graphql搭建一個的普通GraphQL查詢(query)的例子传惠,包括講解GraphQL的部分類型和參數(shù),已經(jīng)掌握了的同學(xué)可以跳過稻扬。
- 先跑個hello world
新建一個graphql文件夾卦方,然后在該目錄下打開終端,執(zhí)行npm init --y初始化一個packjson文件泰佳。
安裝依賴包:npm install --save -D express express-graphql graphql
新建sehema.js文件愿汰,填上下面的代碼
//schema.js
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
} = require('graphql');
const queryObj = new GraphQLObjectType({
name: 'myFirstQuery',
description: 'a hello world demo',
fields: {
hello: {
name: 'a hello world query',
description: 'a hello world demo',
type: GraphQLString,
resolve(parentValue, args, request) {
return 'hello world !';
}
}
}
});
module.exports = new GraphQLSchema({
query: queryObj
});
這里的意思是新建一個簡單的查詢困后,查詢名字叫hello,會返回字段hello world !衬廷,其他的是定義名字和查詢結(jié)果類型的意思摇予。
同級目錄下新建server.js文件,填上下面的代碼
// server.js
const express = require('express');
const expressGraphql = require('express-graphql');
const app = express();
const schema = require('./schema');
app.use('/graphql', expressGraphql({
schema,
graphiql: true
}));
app.get('/', (req, res) => res.end('index'));
app.listen(8000, (err) => {
if(err) {throw new Error(err);}
console.log('*** server started ***');
});
這部分代碼是用express跑起來一個服務(wù)器吗跋,并通過express-graphql把graphql掛載到服務(wù)器上侧戴。
運行一下node server,并打開http://localhost:8000/
如圖跌宛,說明服務(wù)器已經(jīng)跑起來了
打開
http://localhost:8000/graphql
酗宋,是類似下面這種界面說明已經(jīng)graphql服務(wù)已經(jīng)跑起來了!在左側(cè)輸入 (graphql的查詢語法這里不做說明)
{
hello
}
點擊頭部的三角形的運行按鈕疆拘,右側(cè)就會顯示你查詢的結(jié)果了
2. 不僅僅是hello world
先簡單講解一下代碼:
const queryObj = new GraphQLObjectType({
name: 'myFirstQuery',
description: 'a hello world demo',
fields: {}
});
GraphQLObjectType是GraphQL.js定義的對象類型蜕猫,包括name、description 和fields三個屬性哎迄,其中name和description 是非必填的回右。fields是解析函數(shù),在這里可以理解為查詢方法
hello: {
name: 'a hello world query',
description: 'a hello world demo',
type: GraphQLString,
resolve(parentValue, args, request) {
return 'hello world !';
}
}
對于每個fields漱挚,又有name翔烁,description,type旨涝,resolve參數(shù)蹬屹,這里的type可以理解為hello方法返回的數(shù)據(jù)類型,resolve就是具體的處理方法白华。
說到這里有些同學(xué)可能還不滿足慨默,如果我想每次查詢都想帶上一個參數(shù)該怎么辦,如果我想查詢結(jié)果有多條數(shù)據(jù)又怎么處理弧腥?
下面修改schema.js文件业筏,來一個加強(qiáng)版的查詢(當(dāng)然,你可以整理一下代碼鸟赫,我這樣寫是為了方便閱讀)
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLBoolean
} = require('graphql');
const queryObj = new GraphQLObjectType({
name: 'myFirstQuery',
description: 'a hello world demo',
fields: {
hello: {
name: 'a hello world query',
description: 'a hello world demo',
type: GraphQLString,
args: {
name: { // 這里定義參數(shù)蒜胖,包括參數(shù)類型和默認(rèn)值
type: GraphQLString,
defaultValue: 'Brian'
}
},
resolve(parentValue, args, request) { // 這里演示如何獲取參數(shù),以及處理
return 'hello world ' + args.name + '!';
}
},
person: {
name: 'personQuery',
description: 'query a person',
type: new GraphQLObjectType({ // 這里定義查詢結(jié)果包含name,age,sex三個字段抛蚤,并且都是不同的類型台谢。
name: 'person',
fields: {
name: {
type: GraphQLString
},
age: {
type: GraphQLInt
},
sex: {
type: GraphQLBoolean
}
}
}),
args: {
name: {
type: GraphQLString,
defaultValue: 'Charming'
}
},
resolve(parentValue, args, request) {
return {
name: args.name,
age: args.name.length,
sex: Math.random() > 0.5
};
}
}
}
});
module.exports = new GraphQLSchema({
query: queryObj
});
重啟服務(wù)后,繼續(xù)打開http://localhost:8000/graphql岁经,在左側(cè)輸入
{
hello(name:"charming"),
person(name:"charming"){
name,
sex,
age
}
}
右側(cè)就會顯示出:
你可以在左側(cè)僅輸入person方法的sex和age兩個字段朋沮,這樣就會只返回sex和age的信息。動手試一試吧!
{
person(name:"charming"){
sex,
age
}
}
當(dāng)然,結(jié)果的順序也是按照你輸入的順序排序的樊拓。
定制化的數(shù)據(jù)纠亚,完全根據(jù)你查什么返回什么結(jié)果。這就是GraphQL被稱作API查詢語言的原因筋夏。
四蒂胞、GraphQL實戰(zhàn)
下面我將搭配koa實現(xiàn)一個GraphQL查詢的例子,逐步從簡單koa服務(wù)到mongodb的數(shù)據(jù)插入查詢条篷,再到GraphQL的使用骗随,最終實現(xiàn)用GraphQL對數(shù)據(jù)庫進(jìn)行增刪查改。
項目效果大概如下:
有點意思吧赴叹?那就開始吧~
先把文件目錄建構(gòu)建好
-
初始化項目
初始化項目鸿染,在根目錄下運行npm init --y,
然后安裝一些包:npm install koa koa-static koa-router koa-bodyparser --save -D
新建config乞巧、controllers涨椒、graphql、mongodb绽媒、public蚕冬、router這幾個文件夾。裝逼的操作是在終端輸入mkdir config controllers graphql mongodb public router回車些椒,ok~ 跑一個koa服務(wù)器
新建一個server.js文件,寫入以下代碼
// server.js
import Koa from 'koa'
import Router from 'koa-router'
import bodyParser from 'koa-bodyparser'
const app = new Koa()
const router = new Router();
const port = 4000
app.use(bodyParser());
router.get('/hello', (ctx, next) => {
ctx.body="hello world"
});
app.use(router.routes())
.use(router.allowedMethods());
app.listen(port);
console.log('server listen port: ' + port)
這里的意思是新建一個簡單的查詢掸刊,查詢名字叫hello免糕,會返回字段hello world !,其他的是定義名字和查詢結(jié)果類型的意思忧侧。
同級目錄下新建server.js文件石窑,填上下面的代碼
// server.js
const express = require('express');
const expressGraphql = require('express-graphql');
const app = express();
const schema = require('./schema');
app.use('/graphql', expressGraphql({
schema,
graphiql: true
}));
app.get('/', (req, res) => res.end('index'));
app.listen(8000, (err) => {
if(err) {throw new Error(err);}
console.log('*** server started ***');
});
這部分代碼是用express
跑起來一個服務(wù)器,并通過express-graphql
把graphql
掛載到服務(wù)器上蚓炬。
- 運行一下
node server
松逊,并打開http://localhost:8000/
如圖,說明服務(wù)器已經(jīng)跑起來了
打開http://localhost:8000/graphql肯夏,是類似下面這種界面說明已經(jīng)graphql服務(wù)已經(jīng)跑起來了经宏!
在左側(cè)輸入 (graphql的查詢語法這里不做說明)
{
hello
}
點擊頭部的三角形的運行按鈕,右側(cè)就會顯示你查詢的結(jié)果了
- 不僅僅是hello world
先簡單講解一下代碼:
const queryObj = new GraphQLObjectType({
name: 'myFirstQuery',
description: 'a hello world demo',
fields: {}
});
GraphQLObjectType是GraphQL.js定義的對象類型驯击,包括name徊都、description 和fields三個屬性主之,其中name和description 是非必填的槽奕。fields是解析函數(shù)枉长,在這里可以理解為查詢方法
hello: {
name: 'a hello world query',
description: 'a hello world demo',
type: GraphQLString,
resolve(parentValue, args, request) {
return 'hello world !';
}
}
對于每個fields,又有name吼蚁,description肝匆,type,resolve參數(shù)能曾,這里的type可以理解為hello方法返回的數(shù)據(jù)類型,resolve就是具體的處理方法驼唱。
說到這里有些同學(xué)可能還不滿足玫恳,如果我想每次查詢都想帶上一個參數(shù)該怎么辦,如果我想查詢結(jié)果有多條數(shù)據(jù)又怎么處理?
下面修改schema.js文件审孽,來一個加強(qiáng)版的查詢(當(dāng)然式散,你可以整理一下代碼,我這樣寫是為了方便閱讀)
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLBoolean
} = require('graphql');
const queryObj = new GraphQLObjectType({
name: 'myFirstQuery',
description: 'a hello world demo',
fields: {
hello: {
name: 'a hello world query',
description: 'a hello world demo',
type: GraphQLString,
args: {
name: { // 這里定義參數(shù)乖篷,包括參數(shù)類型和默認(rèn)值
type: GraphQLString,
defaultValue: 'Brian'
}
},
resolve(parentValue, args, request) { // 這里演示如何獲取參數(shù),以及處理
return 'hello world ' + args.name + '!';
}
},
person: {
name: 'personQuery',
description: 'query a person',
type: new GraphQLObjectType({ // 這里定義查詢結(jié)果包含name,age,sex三個字段鲸沮,并且都是不同的類型。
name: 'person',
fields: {
name: {
type: GraphQLString
},
age: {
type: GraphQLInt
},
sex: {
type: GraphQLBoolean
}
}
}),
args: {
name: {
type: GraphQLString,
defaultValue: 'Charming'
}
},
resolve(parentValue, args, request) {
return {
name: args.name,
age: args.name.length,
sex: Math.random() > 0.5
};
}
}
}
});
module.exports = new GraphQLSchema({
query: queryObj
});
重啟服務(wù)后,繼續(xù)打開http://localhost:8000/graphql毕荐,在左側(cè)輸入
{
hello(name:"charming"),
person(name:"charming"){
name,
sex,
age
}
}
右側(cè)就會顯示出:
你可以在左側(cè)僅輸入person方法的sex和age兩個字段员寇,這樣就會只返回sex和age的信息蝶锋。動手試一試吧!
{
person(name:"charming"){
sex,
age
}
}
當(dāng)然,結(jié)果的順序也是按照你輸入的順序排序的躯舔。
定制化的數(shù)據(jù)粥庄,完全根據(jù)你查什么返回什么結(jié)果布讹。這就是GraphQL被稱作API查詢語言的原因描验。
四睡扬、GraphQL實戰(zhàn)
參考:https://blog.csdn.net/qq_41882147/article/details/82966783