优势:按需请求,不多不少!
一、环境配置
1.安装Visual Studio Code的最新版本
2.安装MongoDB的最新Windows或Linux版本承载数据,把数据导入graphql数据库中,集合名称为:base.diseases,是国家标准疾病库字典,本文演示数据只有很少的三个键值对:code,name,assistant,如果你有1024个,则慢慢加吧!不过我有个工具可以批量秒生成!
3.安装NodeJS的最新版本用于承载项目。
4.升级npm到最新版本,执行:npm i -g npm
5.找个美好的地方创建graphql-demo目录,环境配置完毕。
二、初始化项目
1.打开Visual Studio Code开发工具,并立即打开刚刚创建好的graphql-demo目录。
2.在菜单“查看”中单击“终端”,或者按Ctrl+`,就是波浪线键上靠下边的那个反引号,打开终端,执行:npm init -y,会出现package.js文件,说明创建成功,注意观察一下此文件的内容,具体内容请查阅网络资料吧,这里不再阐述。
3.安装应用程序相关的必须依赖包(注意用空隔隔开):npm i nodemon mongoose express express-graphql graphql body-parser,安装完毕后,在package.js中会有如下内容:
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,内容如下,你直接拷贝一下即可。
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 业务接口
// app.use('/api/diseases', require('./routes/diseases'))
// // 引入 GraphQL 业务接口
// // 本接口为测试使用
// 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>
接口服务
</title>
</head>
<br><br><br><br><br>
<center>
<h1>服务正常</h1>
<h1>感谢使用</h1>
<h1><font
color="red">大仙出游</font></h1>
</center>
`
//
测试消息
app.get('/', (req, res) => res.send(html))
// 监听服务
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.测试程序能否正常运行:终端里执行:npm run serve,出现
OK! Mongoose Connected. Version: 5.5.2
Server listening on http://localhost:3001 http://0.0.0.0:3001
说明正常,打开浏览器,输入http://localhost:3001并回车,出现
说明服务正常。
三、开发 REST API 项目
1、新建目录models,用于存放模型,在目录内创建文件,名为Disease.js,定义集合结构,并编辑内容为:
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,用于存放路由文件,在目录内创建文件名,为diseases.js,实现相关路由,并编辑内容为:
// @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: '未查到数据,请先添加!' })
} 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}数据` })
} else {
res.json(data)
}
})
.catch(err => res.status(404).json(err))
}
)
3、测试REST路由能否正常使用,在server.js中,把下面的
// // 引入 REST API 业务接口
// app.use('/api/diseases', require('./routes/diseases'))
取消注释,会发现终端窗口自动编译并重启服务,然后在浏览器中输入:http://localhost:3001/api/diseases,将会获取所有数据,你从网页上复制一个_id值,再输入:http://localhost:3001/api/diseases/5c8d18e4e905ba32d039cd8f,会获取单个数据。说明路由正常
四、开发graphql项目
1、在graphql-demo目录下新建目录graphql,在graphql目录下新建types目录,用于存放类型文件。在types目录中新建Disease.js文件,内容如下:
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同级,用于存放架构文件。在schemas目录中新建RootSchema.js文件,内容如下
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、测试路由能否正常使用,在server.js中的
// // 引入 GraphQL 业务接口
// // 本接口为测试使用
// 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,
// }))
取消注释,会发现命令行窗口自动编译并重启服务,然后在浏览器中输入:http://localhost:3001/api/graphql/test,出现:
说明路由正常。单击右边的Docs,出现:
单击红色的query右边的root,出现:
然后在最左边的框中输入:{
getDiseasesByPagesAndSizes(pages:1,sizes:5){
code
}
}
然后单击运行,出现:
再次编辑左边的内容,再执行,出现:
说明服务正常,你再加个assistant试下效果:
说明,查询的字段,可以根据实际需要进行自定义了。同理添加其它服务即可。
五、在第三方或当前应用程序中调用graphql,本文中将使用EJS引擎,并且在当前项目中实现
1.安装EJS依赖包,终端执行:npm i ejs
2.在根目录下创建views目录,在views目录下创建test.ejs,内容如下:(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上边增加如下代码
// 测试接口,注意get参数用反引号,其中不要有空格,否则会有%编码,id的值要从数据库中找一个真实存在的即可
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,在控制台将看到:
说明调用成功。看到页面
有数据,说明一切OK了!
再添加一个根据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 })
})
})
浏览器调用:http://localhost:3001/test/5c8d18e4e905ba32d039c84f,如下界面:
再添加一个分页的,这次只查分页数据了,代码如下:
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 })
})
})
浏览器调用:http://localhost:3001/test/4/10,界面如下:
总结,GraphQL是一个非常灵活的查询,随时适应需求变化,再也不用为无休止的需求而烦恼了!立刻马上转向GraphQL吧!
祝您成功!