優(yōu)勢(shì):按需請(qǐng)求砍艾,不多不少悯衬!
一码耐、環(huán)境配置
1.安裝Visual Studio Code的最新版本
2.安裝MongoDB的最新Windows或Linux版本承載數(shù)據(jù)追迟,把數(shù)據(jù)導(dǎo)入graphql數(shù)據(jù)庫中,集合名稱為:base.diseases骚腥,是國(guó)家標(biāo)準(zhǔn)疾病庫字典敦间,本文演示數(shù)據(jù)只有很少的三個(gè)鍵值對(duì):code,name,assistant,如果你有1024個(gè)束铭,則慢慢加吧廓块!不過我有個(gè)工具可以批量秒生成!
3.安裝NodeJS的最新版本用于承載項(xiàng)目契沫。
4.升級(jí)npm到最新版本带猴,執(zhí)行:npm i -g npm
5.找個(gè)美好的地方創(chuàng)建graphql-demo目錄,環(huán)境配置完畢懈万。
二拴清、初始化項(xiàng)目
1.打開Visual Studio Code開發(fā)工具,并立即打開剛剛創(chuàng)建好的graphql-demo目錄会通。
2.在菜單“查看”中單擊“終端”口予,或者按Ctrl+`,就是波浪線鍵上靠下邊的那個(gè)反引號(hào)涕侈,打開終端沪停,執(zhí)行:npm init -y,會(huì)出現(xiàn)package.js文件驾凶,說明創(chuàng)建成功牙甫,注意觀察一下此文件的內(nèi)容掷酗,具體內(nèi)容請(qǐng)查閱網(wǎng)絡(luò)資料吧,這里不再闡述窟哺。
3.安裝應(yīng)用程序相關(guān)的必須依賴包(注意用空隔隔開):npm i nodemon mongoose express express-graphql graphql body-parser泻轰,安裝完畢后,在package.js中會(huì)有如下內(nèi)容:
4.修改package.js的配置且轨,把
"scripts":
{
????"test": "echo \"Error: no test specified\" && exit 1"
??}
改為
"scripts":
{
"test": "echo \"Error: no test specified\" && exit 1",
"serve": "nodemon server.js",
??}
5.在graphql-demo目錄下浮声,新建主程序文件:server.js,內(nèi)容如下旋奢,你直接拷貝一下即可泳挥。
const?mongoose?= require('mongoose')
mongoose
.connect('mongodb://localhost:27017/graphql', { useNewUrlParser:?true?})
.then(() =>?{
console.log('OK!', 'Mongoose Connected.', 'Version:', mongoose.version)
const?bodyParser?= require('body-parser')
const?app?= require('express')()
// 使用 body-parser 中間件
app.use(bodyParser.urlencoded({ extended:?false?}))
app.use(bodyParser.json())
// // 引入 REST API 業(yè)務(wù)接口
// app.use('/api/diseases', require('./routes/diseases'))
// // 引入 GraphQL 業(yè)務(wù)接口
// // 本接口為測(cè)試使用
// app.use('/api/graphql/test', require('express-graphql')({
// schema: require('./graphql/schemas/RootSchema'),
// graphiql: true,
// }))
// // 本接口為正式使用
// app.use('/api/graphql', require('express-graphql')({
// schema: require('./graphql/schemas/RootSchema'),
// graphiql: false,
// }))
const?html?= `
<!DOCTYPE
html>
<head>
<title>
接口服務(wù)
</title>
</head>
<br><br><br><br><br>
<center>
<h1>服務(wù)正常</h1>
<h1>感謝使用</h1>
<h1><font
color="red">大仙出游</font></h1>
</center>
`
//
測(cè)試消息
app.get('/', (req, res) =>?res.send(html))
// 監(jiān)聽服務(wù)
const?host?= '0.0.0.0'
const?port?= 3001
app.listen(port, host, () =>?{ console.log(`Server listening on http://localhost:${port}?http://${host}:${port}`)
})
})
.catch((err) =>?{
console.log(err)
})
6.測(cè)試程序能否正常運(yùn)行:終端里執(zhí)行:npm run serve,出現(xiàn)
OK! Mongoose Connected. Version: 5.5.2
Server listening on http://localhost:3001 http://0.0.0.0:3001
說明正常至朗,打開瀏覽器屉符,輸入http://localhost:3001并回車,出現(xiàn)
說明服務(wù)正常锹引。
三矗钟、開發(fā) REST API 項(xiàng)目
1、新建目錄models嫌变,用于存放模型吨艇,在目錄內(nèi)創(chuàng)建文件,名為Disease.js腾啥,定義集合結(jié)構(gòu)东涡,并編輯內(nèi)容為:
const?mongoose?= require('mongoose')
const?Schema?= mongoose.Schema
// Create Schema
const?ObjectSchema?= new?Schema({
code:?{
type:?String,
required:?true
},
assistant:?{
type:?String
},
name:?{
type:?String,
required:?true
}
})
module.exports?= Disease?= mongoose.model('base.diseases', ObjectSchema)
2、新建目錄routes倘待,用于存放路由文件疮跑,在目錄內(nèi)創(chuàng)建文件名,為diseases.js延柠,實(shí)現(xiàn)相關(guān)路由祸挪,并編輯內(nèi)容為:
// @POST & GET & PUT & DELETE => CRUD
const?express?= require('express')
const?router?= express.Router()
const?object?= require('../models/Disease')
router.get(
'/test',
(req, res) =>?{
res.json('OK')
}
)
router.get(
'/',
(req, res) =>?{
object
.find()
.then(data?=>?{
if?(!data)
{
res.status(404).json({ msg:?'未查到數(shù)據(jù)锣披,請(qǐng)先添加贞间!'?})
} else?{
res.json(data)
}
})
.catch(err?=>?res.status(404).json(err))
}
)
router.get(
'/:id',
(req, res) =>?{
const?id?= req.params.id
console.log(id)
object
.findOne({ _id:?id?})
.then(data?=>?{
if?(!data)
{
res.status(404).json({ msg:?`未查到 ${id}數(shù)據(jù)`?})
} else?{
res.json(data)
}
})
.catch(err?=>?res.status(404).json(err))
}
)
3、測(cè)試REST路由能否正常使用雹仿,在server.js中增热,把下面的
// // 引入 REST API 業(yè)務(wù)接口
// app.use('/api/diseases', require('./routes/diseases'))
取消注釋,會(huì)發(fā)現(xiàn)終端窗口自動(dòng)編譯并重啟服務(wù)胧辽,然后在瀏覽器中輸入:http://localhost:3001/api/diseases峻仇,將會(huì)獲取所有數(shù)據(jù),你從網(wǎng)頁上復(fù)制一個(gè)_id值邑商,再輸入:http://localhost:3001/api/diseases/5c8d18e4e905ba32d039cd8f摄咆,會(huì)獲取單個(gè)數(shù)據(jù)凡蚜。說明路由正常
四、開發(fā)graphql項(xiàng)目
1吭从、在graphql-demo目錄下新建目錄graphql朝蜘,在graphql目錄下新建types目錄,用于存放類型文件涩金。在types目錄中新建Disease.js文件谱醇,內(nèi)容如下:
const?{
GraphQLObjectType,
GraphQLString
} = require('graphql')
const?objectType?= new?GraphQLObjectType({
name:?'Disease',
fields:?{
_id:?{
type:?GraphQLString
},
code:?{
type:?GraphQLString
},
assistant:?{
type:?GraphQLString
},
name:?{
type:?GraphQLString
}
}
})
module.exports?= objectType
2、在graphql-demo目錄下的graphql目錄下新建schemas目錄步做,和types同級(jí)副渴,用于存放架構(gòu)文件。在schemas目錄中新建RootSchema.js文件全度,內(nèi)容如下
const?objectDiseaseModel?= require('../../models/Disease')
const?objectDiseaseType?= require('../types/Disease')
const?{
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLList,
GraphQLSchema
} = require('graphql')
const?rootSchema?= new?GraphQLObjectType({
name:?'root',
fields:?{
getDisease:?{
type:?objectDiseaseType,
args:?{
id:?{ type:?GraphQLString?}
},
async?resolve(parent, args)
{
return?await?objectDiseaseModel.findOne({ "_id":?args.id?})
}
},
getDiseases:?{
type:?GraphQLList(objectDiseaseType),
async?resolve(parent, args)
{
return?await?objectDiseaseModel.find({})
}
},
getDiseasesByPagesAndSizes:?{
type:?GraphQLList(objectDiseaseType),
args:?{
pages:?{ type:?GraphQLInt, defaultValue:?1?},
sizes:?{ type:?GraphQLInt, defaultValue:?10?}
},
async?resolve(parent, args)
{
return?await?objectDiseaseModel
.find()
.sort({ code:?1?})
.skip((args.pages?- 1)
* args.sizes)
.limit(args.sizes)
}
},
}
})
module.exports?= new?GraphQLSchema({ query:?rootSchema?})
3煮剧、測(cè)試路由能否正常使用,在server.js中的
// // 引入 GraphQL 業(yè)務(wù)接口
// // 本接口為測(cè)試使用
// app.use('/api/graphql/test', require('express-graphql')({
// schema: require('./graphql/schemas/RootSchema'),
// graphiql: true,
// }))
// // 本接口為正式使用
// app.use('/api/graphql', require('express-graphql')({
// schema: require('./graphql/schemas/RootSchema'),
// graphiql: false,
// }))
取消注釋将鸵,會(huì)發(fā)現(xiàn)命令行窗口自動(dòng)編譯并重啟服務(wù)轿秧,然后在瀏覽器中輸入:http://localhost:3001/api/graphql/test,出現(xiàn):
說明路由正常咨堤。單擊右邊的Docs菇篡,出現(xiàn):
單擊紅色的query右邊的root,出現(xiàn):
然后在最左邊的框中輸入:{
??getDiseasesByPagesAndSizes(pages:1,sizes:5){
????code
??}
}
然后單擊運(yùn)行一喘,出現(xiàn):
再次編輯左邊的內(nèi)容驱还,再執(zhí)行,出現(xiàn):
說明服務(wù)正常凸克,你再加個(gè)assistant試下效果:
說明议蟆,查詢的字段,可以根據(jù)實(shí)際需要進(jìn)行自定義了萎战。同理添加其它服務(wù)即可咐容。
五、在第三方或當(dāng)前應(yīng)用程序中調(diào)用graphql蚂维,本文中將使用EJS引擎戳粒,并且在當(dāng)前項(xiàng)目中實(shí)現(xiàn)
1.安裝EJS依賴包,終端執(zhí)行:npm i ejs
2.在根目錄下創(chuàng)建views目錄虫啥,在views目錄下創(chuàng)建test.ejs蔚约,內(nèi)容如下:(error.ejs,自己寫吧)
<!DOCTYPE?html>
<html>
<head>
<meta?charset="UTF-8">
<meta?name="viewport"?content="width=device-width,
initial-scale=1.0">
<meta?http-equiv="X-UA-Compatible"?content="ie=edge">
<title>GraphQL
Test</title>
</head>
<body>
<h1>GraphQL
Test</h1>
<h2>Author:<%=author%></h2>
<h2>Message:<%=message%></h2>
<%if(disease){%>
<p>disease.code:<%=disease.code%></p>
<p>disease.name:<%=disease.name%></p>
<%}%>
<%if(diseasesplit){%>
<h1>Disease
Array</h1>
<ul>
<%
diseasesplit.forEach((disease)=>{ %>
<li><%=disease._id%>
- <%=disease.code%>
- <%=disease.name%></li>
<%
}) %>
</ul>
<%}%>
</body>
</html>
3.在const html上邊增加如下代碼
// 測(cè)試接口涂籽,注意get參數(shù)用反引號(hào)苹祟,其中不要有空格,否則會(huì)有%編碼,id的值要從數(shù)據(jù)庫中找一個(gè)真實(shí)存在的即可
app.set('view engine', 'ejs')
const?axios?= require('axios')
app.get(
'/test',
(req, res) =>?{
axios
.get(`http://localhost:3001/api/graphql/?query={getDisease(id:"5c8d18e4e905ba32d039cd7d"){code,name}getDiseasesByPagesAndSizes(pages:2,sizes:5){_id,code,name}}`)
.then((response) =>?{
console.log(response.data.data.getDisease)
console.log(response.data.data.getDiseasesByPagesAndSizes)
res.render('test',
{ author:?'Daisen
Travel', message:?'Hello
there!', disease:?response.data.data.getDisease, diseasesplit:?response.data.data.getDiseasesByPagesAndSizes?})
})
.catch((error) =>?{
console.log(error)
res.render('error',
{ error?})
})
})
然后在瀏覽器輸入地址:http://localhost:3001/test树枫,在控制臺(tái)將看到:
說明調(diào)用成功直焙。看到頁面
有數(shù)據(jù)砂轻,說明一切OK了箕般!
再添加一個(gè)根據(jù)id查詢的,代碼如下:
app.get(
'/test/:id',
(req, res) =>?{
const?{ id?} = req.params
axios
.get(`http://localhost:3001/api/graphql/?query={getDisease(id:"${id}"){code,name}getDiseasesByPagesAndSizes(pages:2,sizes:5){_id,code,name}}`)
.then((response) =>?{
console.log(response.data.data.getDisease)
res.render('test',
{ author:?'Daisen
Travel', message:?'Hello
there!', disease:?response.data.data.getDisease, diseasesplit:?response.data.data.getDiseasesByPagesAndSizes?})
})
.catch((error) =>?{
console.log(error)
res.render('error',
{ error?})
})
})
瀏覽器調(diào)用:http://localhost:3001/test/5c8d18e4e905ba32d039c84f舔清,如下界面:
再添加一個(gè)分頁的丝里,這次只查分頁數(shù)據(jù)了,代碼如下:
app.get(
'/test/:pages/:sizes',
(req, res) =>?{
const?{ pages, sizes?} = req.params
axios
// .get(`http://localhost:3001/api/graphql/?query={getDisease(id:"5c8d18e4e905ba32d039cd7d"){code,name}getDiseasesByPagesAndSizes(pages:${pages},sizes:${sizes}){_id,code,name}}`)
.get(`http://localhost:3001/api/graphql/?query={getDiseasesByPagesAndSizes(pages:${pages},sizes:${sizes}){_id,code,name}}`)
.then((response) =>?{
// console.log(response.data.data.getDisease)
res.render('test',
{ author:?'Daisen
Travel', message:?'Hello
there!', disease:?response.data.data.getDisease, diseasesplit:?response.data.data.getDiseasesByPagesAndSizes?})
})
.catch((error) =>?{
console.log(error)
res.render('error',
{ error?})
})
})
瀏覽器調(diào)用:http://localhost:3001/test/4/10体谒,界面如下:
總結(jié)杯聚,GraphQL是一個(gè)非常靈活的查詢,隨時(shí)適應(yīng)需求變化抒痒,再也不用為無休止的需求而煩惱了幌绍!立刻馬上轉(zhuǎn)向GraphQL吧!
祝您成功故响!