文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
四、Koa 中集成 GraphQl 实现 Server API
下载数据库文件解压并导入 mongodb 即可 https://blog.poetries.top/db/koa.zip
- 导入 mongodb 数据库
mongorestore -h localhost:27017 -d koa-demo(数据库名称,不存在会自动创建) ./dump(本地数据文件路径)
- 导出 mongodb 数据库
mongodump -h localhost:27017 -d test(数据库名称) -o ./dump
文档地址 https://github.com/chentsulin/koa-graphql
npm install graphql koa-graphql koa-mount --save
实现导航列表 API、文章分类 API、文章列表 API、文章详情 API 、文章列表分页查询 API、以及文章列表关联文章分类实现聚合 API
4.1 app 完善配置
// app.js var Koa=require('koa'); var router = require('koa-router')(); const mount = require('koa-mount'); const graphqlHTTP = require('koa-graphql'); var GraphQLDefaultSchema=require('./schema/default.js') const DB=require('./model/db.js'); var app=new Koa(); //配置中间件 app.use(mount('/graphql', graphqlHTTP({ schema: GraphQLDefaultSchema, graphiql: true }))); router.get('/',async (ctx)=>{ ctx.body="首页"; }) router.get('/getNavList',async (ctx)=>{ var navList=await DB.find('nav',{}); ctx.body=navList; }) app.use(router.routes()); /*启动路由*/ app.use(router.allowedMethods()); app.listen(4000, ()=>console.log('http://localhost:4000'));
4.2 定义 schema 模型
// schema/default.js const DB=require('../model/db.js'); //文章分类 api 接口 //文章列表 api 接口 (分页) //文章详情 api 接口(api 聚合 获取分类信息) const { GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLFloat, GraphQLList, GraphQLSchema, GraphQLID }=require('graphql') //1、定义导航的 schema var NavSchema=new GraphQLObjectType({ name:'nav', fields:{ _id:{ type:GraphQLString }, title:{ type:GraphQLString },url:{ type:GraphQLString }, sort:{ type:GraphQLInt }, status:{ type:GraphQLString }, add_time:{ type:GraphQLString } } }) //定义文章分类的 schema var ArticleCateSchema=new GraphQLObjectType({ name:'articlecate', fields:{ _id:{type:GraphQLString}, title:{type:GraphQLString}, description:{ type: GraphQLString }, keywords:{ type: GraphQLInt }, pid:{type:GraphQLInt}, add_time:{ type: GraphQLString }, status:{ type: GraphQLInt } } }) //定义文章的 schema var ArticleSchema=new GraphQLObjectType({ name:'article', fields:{ _id:{type:GraphQLID}, pid:{type:GraphQLID}, title:{ type: GraphQLString }, author:{ type: GraphQLString }, status:{type:GraphQLInt}, is_best:{ type: GraphQLInt }, is_hot:{ type: GraphQLInt }, is_new:{ type: GraphQLInt }, keywords:{ type: GraphQLString }, description:{ type: GraphQLString }, content:{ type: GraphQLString }, sort:{ type: GraphQLInt }, // 聚合查询文章分类信息 cateInfo:{ type:ArticleCateSchema, async resolve(parent,args){ // parent.pid 当前新闻的分类 id console.log(parent); var cateResult=await DB.find('articlecate',{"_id":DB.getObjectId(parent.pid)}); return cateResult[0]; } } } }) //订单商品的 Schema (order_item) var OrderItem=new GraphQLObjectType({ name:'orderitem', fields:{ uid:{ type: GraphQLID }, order_id: { type: GraphQLID }, product_title: { type: GraphQLString }, product_id: { type: GraphQLID }, product_img: { type: GraphQLString }, product_price: { type: GraphQLFloat }, product_num: { type: GraphQLInt }, add_time: { type: GraphQLString } } }) //订单的 Schema var OrderSchema=new GraphQLObjectType({ name:'order', fields:{ _id:{type:GraphQLID}, uid: { type:GraphQLID}, all_price: { type: GraphQLInt }, order_id: { type: GraphQLInt }, name: { type: GraphQLString }, phone: { type: GraphQLString }, address: { type: GraphQLString }, zipcode: { type: GraphQLString }, pay_status:{ type: GraphQLInt}, // 支付状态: 0 表示未支付 1 已经支付 pay_type:{type: GraphQLString}, // 支付类型: alipay wechat order_status: { // 订单状态: 0 已下单 1 已付款 2 已配货 3、发货 4、交易成功 5、退货 6、取消 type: GraphQLInt }, add_time: { type: GraphQLString }, // 聚合查询订单关联的商品列表信息 orderItems:{ type:GraphQLList(OrderItem), async resolve(parent,args){ //获取当前订单对应的商品 parent._id 就是 objectId var orderItemList=await DB.find('order_item',{"order_id":parent._id}); return orderItemList; } } } }) //2、定义一个根 配置调用 Schema 的方法 var RootSchema=new GraphQLObjectType({ name:'root', fields:{ navList:{ type:GraphQLList(NavSchema), async resolve(parent,args){ var navList=await DB.find('nav',{}); return navList; } }, oneNavList:{ type:NavSchema, args:{ _id:{ type:GraphQLString }, status:{ type:GraphQLString } }, async resolve(parent,args){ var oneNavList=await DB.find('nav',{"_id":DB.getObjectId(args._id),"status":args.status}); return oneNavList[0]; } }, articleCateList:{ type:GraphQLList(ArticleCateSchema), async resolve(parent,args){ var articlecateList=await DB.find('articlecate',{}); return articlecateList; } }, articleList:{ type:GraphQLList(ArticleSchema), args:{ page:{ type:GraphQLInt }, pageSize:{ type:GraphQLInt } }, // 分页查询文章列表 async resolve(parent,args){ var page=args.page||1; var pageSize=args.pageSize||5; console.log(page,pageSize); var articleList=await DB.find('article',{},{},{ page, pageSize:pageSize, sort:{"add_time":-1} }); return articleList; } }, // 订单列表 orderList:{ type:GraphQLList(OrderSchema), args:{ page:{ type:GraphQLInt } }, async resolve(parent,args){ var page=args.page || 1; var orderList=await DB.find('order',{},{},{ page, pageSize:3 }); return orderList; } }, // 单个订单信息 oneOrderList:{ type:OrderSchema, args:{ _id:{ type:GraphQLID } }, async resolve(parent,args){ var orderList=await DB.find('order',{"_id":DB.getObjectId(args._id)}); return orderList[0]; } } } }) //3、把查询的根 挂载到 GraphQLSchema module.exports=new GraphQLSchema({ query:RootSchema })
4.3 编写数据库操作方法
// model/db.js /** * http://mongodb.github.io/node-mongodb-native * http://mongodb.github.io/node-mongodb-native/3.0/api/ */ //DB 库 var MongoDB=require('mongodb'); var MongoClient =MongoDB.MongoClient; const ObjectID = MongoDB.ObjectID; var Config= { url: 'mongodb://localhost:27017', dbName: 'koa-demo' } class Db{ static getInstance(){ /*1、单例 多次实例化实例不共享的问题*/ if(!Db.instance){ Db.instance=new Db(); } return Db.instance; } constructor(){ this.dbClient=''; /*属性 放 db 对象*/ this.connect(); /*实例化的时候就连接数据库*/ } connect(){ /*连接数据库*/ let _that=this; return new Promise((resolve,reject)=>{ if(!_that.dbClient){ /*1、解决数据库多次连接的问题*/ MongoClient.connect(Config.dbUrl,{ useNewUrlParser: true },(err,client)=>{ if(err){ reject(err) }else{ _that.dbClient=client.db(Config.dbName); resolve(_that.dbClient) } }) }else{ resolve(_that.dbClient); } }) } /* DB.find('user',{}) 返回所有数据 DB.find('user',{},{"title":1}) 返回所有数据 只返回一列 DB.find('user',{},{"title":1},{ 返回第二页的数据 page:2, pageSize:20, sort:{"add_time":-1} }) js 中实参和形参可以不一样 arguments 对象接收实参传过来的数据 * */ find(collectionName,json1,json2,json3){ if(arguments.length==2){ var attr={}; var slipNum=0; var pageSize=0; }else if(arguments.length==3){ var attr=json2; var slipNum=0; var pageSize=0; }else if(arguments.length==4){ var attr=json2; var page=parseInt(json3.page) ||1; var pageSize=parseInt(json3.pageSize)||20; var slipNum=(page-1)*pageSize; if(json3.sort){ var sortJson=json3.sort; }else{ var sortJson={} } }else{ console.log('传入参数错误') } return new Promise((resolve,reject)=>{ this.connect().then((db)=>{ //var result=db.collection(collectionName).find(json); var result =db.collection(collectionName).find(json1,{fields:attr}).skip(slipNum).limit(pageSize).sort(sortJson); result.toArray(function(err,docs){ if(err){ reject(err); return; } resolve(docs); }) }) }) } update(collectionName,json1,json2){ return new Promise((resolve,reject)=>{ this.connect().then((db)=>{ //db.user.update({},{$set:{}}) db.collection(collectionName).updateOne(json1,{ $set:json2 },(err,result)=>{ if(err){ reject(err); }else{ resolve(result); } }) }) }) } insert(collectionName,json){ return new Promise((resolve,reject)=>{ this.connect().then((db)=>{ db.collection(collectionName).insertOne(json,function(err,result){ if(err){ reject(err); }else{ resolve(result); } }) }) }) } remove(collectionName,json){ return new Promise((resolve,reject)=>{ this.connect().then((db)=>{ db.collection(collectionName).removeOne(json,function(err,result){ if(err){ reject(err); }else{ resolve(result); } }) }) }) } getObjectId(id){ /*mongodb 里面查询 _id 把字符串转换成对象*/ return new ObjectID(id); } //统计数量的方法 count(collectionName,json){ return new Promise((resolve,reject)=> { this.connect().then((db)=> { var result = db.collection(collectionName).count(json); result.then(function (count) { resolve(count); } ) }) }) } } module.exports=Db.getInstance();
启动服务
4.4 聚合查询
聚合查询文章分类信息,分类信息的方式要放在 article 的 schema 里面,这样才能聚合查询到
聚合查询结果
查询订单,聚合查询订单关联的商品信息返回,实现类似以下效果
// schema/default.js //订单商品的 Schema (order_item) var OrderItem=new GraphQLObjectType({ name:'orderitem', fields:{ uid:{ type: GraphQLID }, order_id: { type: GraphQLID }, product_title: { type: GraphQLString }, product_id: { type: GraphQLID }, product_img: { type: GraphQLString }, product_price: { type: GraphQLFloat }, product_num: { type: GraphQLInt }, add_time: { type: GraphQLString } } }) //订单的 Schema var OrderSchema=new GraphQLObjectType({ name:'order', fields:{ _id:{type:GraphQLID}, uid: { type:GraphQLID}, all_price: { type: GraphQLInt }, order_id: { type: GraphQLInt }, name: { type: GraphQLString }, phone: { type: GraphQLString }, address: { type: GraphQLString }, zipcode: { type: GraphQLString }, pay_status:{ type: GraphQLInt}, // 支付状态: 0 表示未支付 1 已经支付 pay_type:{type: GraphQLString}, // 支付类型: alipay wechat order_status: { // 订单状态: 0 已下单 1 已付款 2 已配货 3、发货 4、交易成功 5、退货 6、取消 type: GraphQLInt }, add_time: { type: GraphQLString }, // 聚合查询订单关联的商品列表信息 orderItems:{ type:GraphQLList(OrderItem), async resolve(parent,args){ //获取当前订单对应的商品 parent._id 就是 objectId var orderItemList=await DB.find('order_item',{"order_id":parent._id}); return orderItemList; } } } }) // 定义一个根 配置调用 Schema 的方法 var RootSchema=new GraphQLObjectType({ name:'root', fields:{ orderList:{ type:GraphQLList(OrderSchema), args:{ page:{ type:GraphQLInt } }, async resolve(parent,args){ var page=args.page || 1; var orderList=await DB.find('order',{},{},{ page, pageSize:3 }); return orderList; } }, oneOrderList:{ type:OrderSchema, args:{ _id:{ type:GraphQLID } }, async resolve(parent,args){ var orderList=await DB.find('order',{"_id":DB.getObjectId(args._id)}); return orderList[0]; } } } })
查询订单详情
需要哪些字段,就返回哪些字段,编辑器会自定提示
4.5 分页查询
//定义文章分类的 schema var ArticleCateSchema=new GraphQLObjectType({ name:'articlecate', fields:{ _id:{type:GraphQLString}, title:{type:GraphQLString}, description:{ type: GraphQLString }, keywords:{ type: GraphQLInt }, pid:{type:GraphQLInt}, add_time:{ type: GraphQLString }, status:{ type: GraphQLInt } } }) //定义文章的 schema var ArticleSchema=new GraphQLObjectType({ name:'article', fields:{ _id:{type:GraphQLID}, pid:{type:GraphQLID}, title:{ type: GraphQLString }, author:{ type: GraphQLString }, status:{type:GraphQLInt}, is_best:{ type: GraphQLInt }, is_hot:{ type: GraphQLInt }, is_new:{ type: GraphQLInt }, keywords:{ type: GraphQLString }, description:{ type: GraphQLString }, content:{ type: GraphQLString }, sort:{ type: GraphQLInt }, // 聚合查询文章分类信息 cateInfo:{ type:ArticleCateSchema, async resolve(parent,args){ // parent.pid 当前新闻的分类 id console.log(parent); var cateResult=await DB.find('articlecate',{"_id":DB.getObjectId(parent.pid)}); return cateResult[0]; } } } }) //2、定义一个根 配置调用 Schema 的方法 var RootSchema=new GraphQLObjectType({ name:'root', fields:{ articleCateList:{ type:GraphQLList(ArticleCateSchema), async resolve(parent,args){ var articlecateList=await DB.find('articlecate',{}); return articlecateList; } }, articleList:{ type:GraphQLList(ArticleSchema), args:{ page:{ type:GraphQLInt }, pageSize:{ type:GraphQLInt } }, // 分页查询文章列表 async resolve(parent,args){ var page=args.page||1; var pageSize=args.pageSize||5; console.log(page,pageSize); var articleList=await DB.find('article',{},{},{ page, pageSize:pageSize, sort:{"add_time":-1} }); return articleList; } }, } })
4.6 实现数据增加、修改、删除
// scehma/default.js //增加 修改 删除 // 定义根 MutationRoot 实现增删改 var MutationSchema=new GraphQLObjectType({ name:"mutation", fields:{ addNav:{ type:NavSchema, args:{ title: {type: new GraphQLNonNull(GraphQLString)}, //表示 title 和 url 是必传字段 url: {type: GraphQLNonNull(GraphQLString)}, sort: {type: GraphQLInt}, status: {type: GraphQLString}, add_time: {type: GraphQLString} }, async resolve(parent, args) { var result = await DB.insert('nav', {title:args.title, url:args.url, sort:args.sort, status:args.status, add_time:new Date().getTime() }); console.log(result.ops[0]); return result.ops[0]; } }, editNav:{ type:NavSchema, args:{ _id:{type: new GraphQLNonNull(GraphQLString)}, title: {type: new GraphQLNonNull(GraphQLString)}, //表示 title 和 url 是必传字段 url: {type: GraphQLNonNull(GraphQLString)}, sort: {type: GraphQLInt}, status: {type: GraphQLString}, add_time: {type: GraphQLString} }, async resolve(parent, args) { var result = await DB.update('nav', {"_id":DB.getObjectId(args._id)},{title:args.title, url:args.url, sort:args.sort, status:args.status, add_time:new Date().getTime() }); // console.log(result); return { _id:args._id, title:args.title, url:args.url, sort:args.sort, status:args.status, add_time:new Date().getTime() } } } , deleteNav:{ type:NavSchema, args:{ _id:{type: new GraphQLNonNull(GraphQLString)}, }, async resolve(parent, args) { var oneNavList = await DB.find('nav', { "_id": DB.getObjectId(args._id)}); var deleteResult = await DB.remove('nav', {"_id":DB.getObjectId(args._id)}); console.log(deleteResult.result.n); if(deleteResult.result.n){ return oneNavList[0]; }else{ return {} } } } } }) // 挂载到 GraphQLSchema module.exports=new GraphQLSchema({ // query:RootSchema, mutation:MutationSchema })
- 新增
可以看到必填字段不填会提示
再次查询列表
- 修改
- 删除
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论