wordpress移动插件,seo推广是什么,南宁网络,何使网站的页面结构更为合理建本文将从GraphQL是什么#xff0c;为什么要使用GraphQL#xff0c;使用GraphQL创建简单例子#xff0c;以及GraphQL实战#xff0c;四个方面对GraphQL进行阐述。说得不对的地方#xff0c;希望大家指出斧正。 github项目地址#xff1a;https://github.com/Charming2015/… 本文将从GraphQL是什么为什么要使用GraphQL使用GraphQL创建简单例子以及GraphQL实战四个方面对GraphQL进行阐述。说得不对的地方希望大家指出斧正。 github项目地址https://github.com/Charming2015/graphql-todolist 一、GraphQL是什么? 关于GraphQL是什么网上一搜一大堆。根据官网的解释就是一种用于 API 的查询语言。 一看到用于API的查询语言我也是一脸懵逼的。博主你在开玩笑吧你的翻译水平不过关API还能查吗API不是后端写好前端调用的吗 的确可以这就是GraphQL强大的地方。 引用官方文档的一句话 ask exactly what you want. 二、为什么要使用GraphQL? 在实际工作中往往会有这种情景出现比如说我需要展示一个游戏名的列表可接口却会把游戏的详细玩法更新时间创建者等各种各样的 无用的 信息都一同返回。 问了后端原因大概如下 原来是为了兼容PC端和移动端用同一套接口或者在整个页面这里需要显示游戏的标题可是别的地方需要显示游戏玩法啊避免多次请求我就全部返回咯或者是因为有时候项目经理想要显示“标题更新时间”有时候想要点击标题展开游戏玩法等等需求所以把游戏相关的信息都一同返回简单说就是 兼容多平台导致字段冗余一个页面需要多次调用 API 聚合数据需求经常改动导致接口很难为单一接口精简逻辑有同学可能会说那也不一定要用GraphQL啊比方说第一个问题不同平台不同接口不就好了嘛 http://api.xxx.com/web/getGameInfo/:gameID
http://api.xxx.com/app/getGameInfo/:gameID
http://api.xxx.com/mobile/getGameInfo/:gameID或者加个参数也行 http://api.xxx.com/getGameInfo/:gameID?platfromweb这样处理的确可以解决问题但是无疑加大了后端的处理逻辑。你真的不怕后端程序员打你 这个时候我们会想接口能不能不写死把静态变成动态 回答是可以的这就是GraphQL所做的! 三、GraphQL尝尝鲜——(GraphQL简单例子) 下面是用GraphQL.js和express-graphql搭建一个的普通GraphQL查询query的例子包括讲解GraphQL的部分类型和参数已经掌握了的同学可以跳过。 1. 先跑个hello world 新建一个graphql文件夹然后在该目录下打开终端执行npm init --y初始化一个packjson文件。安装依赖包npm install --save -D express express-graphql graphql新建schema.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 !其他的是定义名字和查询结果类型的意思。 同级目录下新建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跑起来一个服务器并通过express-graphql把graphql挂载到服务器上。 运行一下node server并打开http://localhost:8000/如图说明服务器已经跑起来了 打开http://localhost:8000/graphql是类似下面这种界面说明已经graphql服务已经跑起来了 在左侧输入 (graphql的查询语法这里不做说明) {hello
}点击头部的三角形的运行按钮右侧就会显示你查询的结果了 2. 不仅仅是hello world 先简单讲解一下代码 const queryObj new GraphQLObjectType({name: myFirstQuery,description: a hello world demo,fields: {}
});GraphQLObjectType是GraphQL.js定义的对象类型包括name、description 和fields三个属性其中name和description 是非必填的。fields是解析函数在这里可以理解为查询方法 hello: {name: a hello world query,description: a hello world demo,type: GraphQLString,resolve(parentValue, args, request) {return hello world !;}}对于每个fields又有namedescriptiontyperesolve参数这里的type可以理解为hello方法返回的数据类型resolve就是具体的处理方法。 说到这里有些同学可能还不满足如果我想每次查询都想带上一个参数该怎么办如果我想查询结果有多条数据又怎么处理 下面修改schema.js文件来一个加强版的查询当然你可以整理一下代码我这样写是为了方便阅读 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: { // 这里定义参数包括参数类型和默认值type: GraphQLString,defaultValue: Brian}},resolve(parentValue, args, request) { // 这里演示如何获取参数以及处理return hello world args.name !;}},person: {name: personQuery,description: query a person,type: new GraphQLObjectType({ // 这里定义查询结果包含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
});重启服务后继续打开http://localhost:8000/graphql在左侧输入 {hello(name:charming),person(name:charming){name,sex,age}
}右侧就会显示出 你可以在左侧仅输入person方法的sex和age两个字段这样就会只返回sex和age的信息。动手试一试吧! {person(name:charming){sex,age}
}当然结果的顺序也是按照你输入的顺序排序的。 定制化的数据完全根据你查什么返回什么结果。这就是GraphQL被称作API查询语言的原因。 四、GraphQL实战 下面我将搭配koa实现一个GraphQL查询的例子逐步从简单koa服务到mongodb的数据插入查询再到GraphQL的使用最终实现用GraphQL对数据库进行增删查改。 项目效果大概如下 有点意思吧那就开始吧~ 先把文件目录建构建好 1. 初始化项目 初始化项目在根目录下运行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~2. 跑一个koa服务器 新建一个server.js文件写入以下代码 // server.js
import Koa from koa
import Router from koa-router
import bodyParser from koa-bodyparserconst app new Koa()
const router new Router();
const port 4000app.use(bodyParser());router.get(/hello, (ctx, next) {ctx.bodyhello world
});app.use(router.routes()).use(router.allowedMethods());app.listen(port);console.log(server listen port: port)执行node server跑起来服务器发现报错了 这是正常的这是因为现在的node版本并没有支持es6的模块引入方式。 百度一下就会有解决方案了比较通用的做法是用babel-polyfill进行转译。 详细的可以看这一个参考操作How To Enable ES6 Imports in Node.JS 具体操作是新建一个start.js文件写入 // start.js
require(babel-register)({presets: [ env ]
})
require(babel-polyfill)
require(./server.js)安装相关包npm install --save -D babel-preset-env babel-polyfill babel-register 修改package.json文件把start: start http://localhost:4000 node start.js这句代码加到下面这个位置 运行一下npm run start打开http://localhost:4000/hello结果如图 说明koa服务器已经跑起来了。 那么前端页面呢 由于本文内容不是讲解前端所以前端代码自行去github复制 在public下新建index.html文件和js文件夹代码直接查看我的项目public目录下的 index.html 和 index-s1.js 文件修改server.js引入koa-static模块。koa-static会把路由的根目录指向自己定义的路径也就是本项目的public路径//server.js
import Koa from koa
import Router from koa-router
import KoaStatic from koa-static
import bodyParser from koa-bodyparserconst app new Koa()
const router new Router();
const port 4000app.use(bodyParser());router.get(/hello, (ctx, next) {ctx.bodyhello world
});app.use(KoaStatic(__dirname /public));
app.use(router.routes()).use(router.allowedMethods());app.listen(port);console.log(server listen port: port)打开http://localhost:4000/发现是类似下面的页面 这时候页面已经可以进行简单的交互但是还没有和后端进行数据交互所以是个静态页面。 3. 搭一个mongodb数据库实现数据增删改查 注意 请先自行下载好mongodb并启动mongodb。 a. 写好链接数据库的基本配置和表设定 在config文件夹下面建立一个index.js这个文件主要是放一下链接数据库的配置代码。 // config/index.js
export default {dbPath: mongodb://localhost/todolist
}在mongodb文件夹新建一个index.js和 schema文件夹 在 schema文件夹文件夹下面新建list.js 在mongodb/index.js下写上链接数据库的代码这里的代码作用是链接上数据库 // mongodb/index.js
import mongoose from mongoose
import config from ../configrequire(./schema/list)export const database () {mongoose.set(debug, true)mongoose.connect(config.dbPath)mongoose.connection.on(disconnected, () {mongoose.connect(config.dbPath)})mongoose.connection.on(error, err {console.error(err)})mongoose.connection.on(open, async () {console.log(Connected to MongoDB , config.dbPath)})
}在mongodb/schema/list.js定义表和字段 //mongodb/schema/list.js
import mongoose from mongooseconst Schema mongoose.Schema
const ObjectId Schema.Types.ObjectIdconst ListSchema new Schema({title: String,desc: String,date: String,id: String,checked: Boolean,meta: {createdAt: {type: Date,default: Date.now()},updatedAt: {type: Date,default: Date.now()}}
})ListSchema.pre(save, function (next) {// 每次保存之前都插入更新时间创建时插入创建时间if (this.isNew) {this.meta.createdAt this.meta.updatedAt Date.now()} else {this.meta.updatedAt Date.now()}next()
})
mongoose.model(List, ListSchema)b. 实现数据库增删查改的控制器 建好表也链接好数据库之后我们就要写一些方法来操作数据库这些方法都写在控制器(controllers)里面。 在controllers里面新建list.js这个文件对应操作list数据的控制器单独拿出来写是为了方便后续项目复杂化的模块化管理。 // controllers/list.js
import mongoose from mongoose
const List mongoose.model(List)
// 获取所有数据
export const getAllList async (ctx, next) {const Lists await List.find({}).sort({date:-1}) // 数据查询if (Lists.length) {ctx.body {success: true,list: Lists}} else {ctx.body {success: false}}
}
// 新增
export const addOne async (ctx, next) {// 获取请求的数据const opts ctx.request.bodyconst list new List(opts)const saveList await list.save() // 保存数据console.log(saveList)if (saveList) {ctx.body {success: true,id: opts.id}} else {ctx.body {success: false,id: opts.id}}
}
// 编辑
export const editOne async (ctx, next) {const obj ctx.request.bodylet hasError falselet error nullList.findOne({id: obj.id}, (err, doc) {if(err) {hasError trueerror err} else {doc.title obj.title;doc.desc obj.desc;doc.date obj.date;doc.save();}})if (hasError) {ctx.body {success: false,id: obj.id}} else {ctx.body {success: true,id: obj.id}}
}// 更新完成状态
export const tickOne async (ctx, next) {const obj ctx.request.bodylet hasError falselet error nullList.findOne({id: obj.id}, (err, doc) {if(err) {hasError trueerror err} else {doc.checked obj.checked;doc.save();}})if (hasError) {ctx.body {success: false,id: obj.id}} else {ctx.body {success: true,id: obj.id}}
}// 删除
export const delOne async (ctx, next) {const obj ctx.request.bodylet hasError falselet msg nullList.remove({id: obj.id}, (err, doc) {if(err) {hasError truemsg err} else {msg doc}})if (hasError) {ctx.body {success: false,id: obj.id}} else {ctx.body {success: true,id: obj.id}}
}c. 实现路由给前端提供API接口 数据模型和控制器都已经设计好了下面就利用koa-router路由中间件来实现请求的接口。 我们回到server.js在上面添加一些代码。如下 // server.js
import Koa from koa
import Router from koa-router
import KoaStatic from koa-static
import bodyParser from koa-bodyparser
import {database} from ./mongodb
import {addOne, getAllList, editOne, tickOne, delOne} from ./controllers/list database() // 链接数据库并且初始化数据模型const app new Koa()
const router new Router();
const port 4000app.use(bodyParser());router.get(/hello, (ctx, next) {ctx.body hello world
});// 把对请求的处理交给处理器。
router.post(/addOne, addOne).post(/editOne, editOne).post(/tickOne, tickOne).post(/delOne, delOne).get(/getAllList, getAllList)app.use(KoaStatic(__dirname /public));
app.use(router.routes()).use(router.allowedMethods());app.listen(port);console.log(server listen port: port)上面的代码就是做了 1. 引入mongodb设置、list控制器
2. 链接数据库
3. 设置每一个设置每一个路由对应的我们定义的的控制器。安装一下mongoosenpm install --save -D mongoose 运行一下npm run start待我们的服务器启动之后就可以对数据库进行操作了。我们可以通过postman来模拟请求先插几条数据 查询全部数据 d. 前端对接接口 前端直接用ajax发起请求就好了平时工作中都是用axios的但是我懒得弄所以直接用最简单的方法就好了。 引入了JQuery之后改写public/js/index.js文件略项目里的public/index-s2.js的代码 项目跑起来发现已经基本上实现了前端发起请求对数据库进行操作了。 至此你已经成功打通了前端后台数据库可以不要脸地称自己是一个小全栈了 不过我们的目的还没有达到——用grapql实现对数据的操作 4. 用grapql实现对数据的操作 GraphQL 的大部分讨论集中在数据获取query但是任何完整的数据平台也都需要一个改变服务端数据的方法。 REST 中任何请求都可能最后导致一些服务端副作用但是约定上建议不要使用 GET 请求来修改数据。GraphQL 也是类似 —— 技术上而言任何查询都可以被实现为导致数据写入。然而建一个约定来规范任何导致写入的操作都应该显式通过变更mutation来发送。 简单说就是GraphQL用mutation来实现数据的修改虽然mutation能做的query也能做但还是要区分开这连个方法就如同REST中约定用GET来请求数据用其他方法来更新数据一样。 a. 实现查询 查询的话比较简单只需要在接口响应时获取数据库的数据然后返回; const objType new GraphQLObjectType({name: meta,fields: {createdAt: {type: GraphQLString},updatedAt: {type: GraphQLString}}
})
let ListType new GraphQLObjectType({name: List,fields: {_id: {type: GraphQLID},id: {type: GraphQLString},title: {type: GraphQLString},desc: {type: GraphQLString},date: {type: GraphQLString},checked: {type: GraphQLBoolean},meta: {type: objType}}
})
const listFields {type: new GraphQLList(ListType),args: {},resolve (root, params, options) {return List.find({}).exec() // 数据库查询}
}
let queryType new GraphQLObjectType({name: getAllList,fields: {lists: listFields,}
})export default new GraphQLSchema({query: queryType
})把增删查改都讲完再更改代码~b. 实现增删查改 一开始说了其实mutation和query用法上没什么区别这只是一种约定。 具体的mutation实现方式如下 const outputType new GraphQLObjectType({name: output,fields: () ({id: { type: GraphQLString},success: { type: GraphQLBoolean },})
});const inputType new GraphQLInputObjectType({name: input,fields: () ({id: { type: GraphQLString },desc: { type: GraphQLString },title: { type: GraphQLString },date: { type: GraphQLString },checked: { type: GraphQLBoolean }})
});
let MutationType new GraphQLObjectType({name: Mutations,fields: () ({delOne: {type: outputType,description: del,args: {id: { type: GraphQLString }},resolve: (value, args) {console.log(args)let result delOne(args)return result}},editOne: {type: outputType,description: edit,args: {listObj: { type: inputType }},resolve: (value, args) {console.log(args)let result editOne(args.listObj)return result}},addOne: {type: outputType,description: add,args: {listObj: { type: inputType }},resolve: (value, args) {console.log(args.listObj)let result addOne(args.listObj)return result}},tickOne: {type: outputType,description: tick,args: {id: { type: GraphQLString },checked: { type: GraphQLBoolean },},resolve: (value, args) {console.log(args)let result tickOne(args)return result}},}),
});export default new GraphQLSchema({query: queryType,mutation: MutationType
})c. 完善其余代码 在实现前端请求Graphql服务器时最困扰我的就是参数以什么样的格式进行传递。后来在Graphql界面玩Graphql的query请求时发现了其中的诀窍… 关于前端请求格式进行一下说明 如上图在玩Graphql的请求时我们就可以直接在控制台network查看请求的格式了。这里我们只需要模仿这种格式当做参数发送给Graphql服务器即可。 记得用反引号 来拼接参数格式。然后用data: {query: params}的格式传递参数代码如下 let data {query: mutation{addOne(listObj:{id: ${that.getUid()},desc: ${that.params.desc},title: ${that.params.title},date: ${that.getTime(that.params.date)},checked: false}){id,success}}}$.post(/graphql, data).done((res) {console.log(res)// do something})最后更改server.jsrouter/index.jscontrollers/list.jspublic/index.js改成github项目对应目录的文件代码即可。 完整项目的目录如下 五、后记 对于Vue开发者可以使用vue-apollo使得前端传参更加优雅~ 六、参考文献 graphql官网教程GraphQL.js30分钟理解GraphQL核心概念我的前端故事----我为什么用GraphQLGraphQL 搭配 Koa 最佳入门实践--------------------- 作者__Charming__ 来源CSDN 原文https://blog.csdn.net/qq_41882147/article/details/82966783 版权声明本文为作者原创文章转载请附上博文链接 内容解析ByCSDN,CNBLOG博客文章一键转载插件