返回介绍

四、Koa 中集成 GraphQl 实现 Server API

发布于 2024-01-31 23:34:12 字数 18690 浏览 0 评论 0 收藏 0

下载数据库文件解压并导入 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文