GraphQL的一些curd操作在express和koa的使用笔记

GraphQL的一些curd操作在express和koa的使用笔记(typescript版本,可以自行转换成js版本)

GraphQL,特点是减少http请求过程中太多无用字段造成的请求量过多,需要什么字段就接受什么字段,加快了http请求过程的速度,减少冗余,同时也有一些它的缺点
1.安装graphql、express-graphql ( Koa的话安装koa-graphql、koa-mount)
yarn add graphql express-graphql --save
//koa选择:
yarn add graphql koa-graphql koa-mount --save 
2.GraphQL的简单使用
2.1graphql的类型
  •  五大基本类型:String 、Int、Float、Boolean、ID,可以在shema声明的时候直接使用
    
  •  复杂类型:
      [类型]:数组类型,例如[Int]表示整数数组和JavaScript一样 小括号定义类型,但是要注意:形参需要定义类型
    
  •  !表示一定要传递 =>传入两个参数,一个必须传,返回一个整数数组
    
2.2 定义schema
import { buildSchema } from "graphql";
const schema = buildSchema(`
  type Account {//自定义复杂类型 自定义类型
       username:String
       password:String
       age:Int
   }
   type Query {
       title:String//返回string类型数据
       author:String//返回string类型数据
       status:Int//返回int类型数据
       account:Account//使用自定义复杂类型,返回Account对象类型
   }
`);
//业务相关实现
const rootValue = {
   title:()=>"字符串",//调用title 返回整个字符串
   Account:()=>({返回一个自定义类型里面的那些参数对象})
}
2.3 复杂例子
import { buildSchema } from "graphql";
const schema = buildSchema(`
   type Account {
       name:String
       age:Int
       sex:String
       salary(city:String):Int   
   }
   type Query {
       getClassMates(classNo:Int!):[String]//返回一个字符串数组
       account(username:String):Account//返回一个Account对象
   }
`);
const rootValue = {//定义的rootValue和schema需要一致
   getClassMates({ classNo }: { classNo: number }):string {//接收参数classNo:Int!,返回一个字符串数组
       //正常这里说从数据库中取得的
       const obj: any = {
           1: ["张三", "李四", "王五"],
           2: ["老六", "李一", "王二"],
           3: ["小七", "老八", "许九"]//等等等
       }
       return obj[classNo];
   },
   account({ username }: { username: string }):any {//返回一个对象,包含了 user,sex, age,salary四个属性的Action对象
       const user = username;
       const sex = 'man';
       const age = 18;
       const salary = ({ city }: { city: string }) => {
           //通过city返回数据
           return '广州';
       }
       return {
           user,
           sex,
           age,
           salary
       }
   }
}
2.4 graphql的使用(express)
import express, { Express } from 'express';
import expressGraphql from 'express-graphql';
const app: Express = express();
app.use(
    '/graphql',
    expressGraphql({
        schema,//newsSchema自己定义的Schema
        rootValue,// 这是自定义属性,就是实现schema相关的业务
        graphiql: true,//开始graphql的调试控制台
    })
);

const port: number | string = 8888 || (process as any).env.PORT;

app.listen(port, () => {
    console.log(`服务器运行在 ${port} 端口中...`);
});
2.5 graphql在koa的使用
import Koa from 'koa';
import koaGraphql from 'koa-graphql';
import mount from 'koa-mount';
import { buildSchema } from "graphql";
app.use(mount('/graphqlDemo', koaGraphql({
    schema,
    rootValue,// 这是自定义属性,就是实现schema相关的业务
    graphiql: true//是否启动调试界面
})));
app.listen(8888,()=>{
    console.log("服务器运行在8888端口");
});
这样就能访问http://localhost:8888/graphql进行graphql调试了
然而上面的那种入门写法是不支持的,主要这样的写法也影响开发的速度,所以要使用graphql的内置函数对象,来实现graphql的使用
3.创建schame的类型 newSchemaType.ts
import { GraphQLObjectType, GraphQLString, GraphQLInt } from "graphql";

//1.定义一个和数据库类型一致的字段fields和名字
export default new GraphQLObjectType<GraphQLObjectType>({
    name:"news",
    fields:{
        _id:{
            type:GraphQLString
        },
        author:{
            type:GraphQLString
        },
        age:{
            type:GraphQLInt
        },
        title:{
            type:GraphQLString
        },
        content:{
            type:GraphQLString
        },
        time:{
            type:GraphQLString
        },
        status:{
            type:GraphQLInt
        }
    }
});
GraphQLObjectType对象类型,GraphQLInt数值类型,GraphQLString字符串类型
4.实现query查询操作对象实例 querySchema.ts
import { GraphQLObjectType, GraphQLString, GraphQLList, GraphQLInt } from "graphql";
import newsSchema from './newSchemaType';

export default new GraphQLObjectType<GraphQLObjectType>({
    name:"query",//表示查询
    fields:{//graphql使用调用的对象
        oneNews:{//定义调用的方法对象集合
            type:newsSchema,//以什么为目标,和上面定义的类型一致的数据返回,(返回类型)
            args:{//调用oneNews方法的参数,(接收参数)
                _id:{type:GraphQLString}
            },           // 第二个参数是args 里面就是定义的参数
            async resolve(_,{_id}){//调用这个方法所执行的操作
            	//模拟从数据库获取到数据返回
                const res:any = await Newss.findById(_id);//然后把数据返回出去
                return res;
            }
        }
        //... 还可以在这增加更多的操作对象,每一个操作对象都是一个新的交互
    }
});
5.实现mutation增删改操作,实例对象 mutationSchema.ts
import { GraphQLObjectType, GraphQLString, GraphQLInt } from "graphql";
import { createNews } from './news/createNews';
import { updateNews } from './news/updateNews';
export default new GraphQLObjectType<GraphQLObjectType>({
    name: "mutation",
    fields: {
    	//模块提取
        createNews,//增加新闻
        updateNews,//修改新闻
        deleteNews: {//删除新闻
            type: GraphQLInt,//返回的类型,一个数值
            args: {//需要的参数
                _id: { type: GraphQLString }
            },
            async resolve(_, { _id }) {//接收到传入的参数
            	//同样模拟去数据库获取数据返回
                const res: any = await Newss.deleteOne({ _id });
                // console.log(res);{ n: 1, ok: 1, deletedCount: 1 }
                return res.deletedCount;//返回是否成功的状态 1就是删除成功
            }
        }
    }
});
6.这时候我们发现我把createNews,updateNews模块提取成一个文件,这时候,我们的代码就更加清晰
创建news文件夹
创建createNews.ts updateNews.ts文件
//createNews.ts
import { GraphQLString, GraphQLInt } from "graphql";
import newsSchema from '../newSchemaType';
export const createNews = {//定义调用的方法 (添加)
    type: newsSchema,//以什么为目标,和上面定义的类型一致的数据返回
    args: {//调用oneNews方法的参数
        author: { type: GraphQLString, defaultValue: "刘先生" },
        age: { type: GraphQLInt, defaultValue: 20, description: "描述" },
        title: { type: GraphQLString },
        content: { type: GraphQLString }
    },           // 第二个参数是args 里面就是定义的参数
    async resolve(_: any, { author, age, title, content }: any) {//执行的操作
        const status: number = 1;
        const time: string = String(new Date());
        //模拟请求添加一条数据
        const res: any = await Newss.create({ author, age, title, content, status, time });
        return res;
    }
}
//updateNews.ts
import { GraphQLString } from "graphql";
import newsSchema from '../newSchemaType';
export const updateNews = {//修改
    type: newsSchema,//返回的类型
    args: {
        _id: { type: GraphQLString },
        title: { type: GraphQLString },
        content: { type: GraphQLString }
    },
    async resolve(_:any, { _id, title, content }:any) {
        const time: string = String(new Date());
        //模拟修改新闻
        const res: any = await Newss.updateOne({ _id }, { title, content, time });
        if (res.n === 1) {
            return await Newss.findById(_id);
        }
        return null;
    }
}
7.最后我们合并query和mutation这curd操作
创建index.ts文件
import { GraphQLSchema } from "graphql";
import querySchema from './querySchema';//查找
import mutationSchema from "./mutationSchema";//增删改
//组合成一个graphql的schema类型
export default new GraphQLSchema({
    query:querySchema,
    mutation:mutationSchema
});
使用: (在server.ts中使用)
koa版本
import Koa from 'koa';
import mount from 'koa-mount';
import koaGraphql from 'koa-graphql';
import SchemaList from './schema';//引入
const app = new Koa();
app.use(mount('/graphql',koaGraphql({
    schema:SchemaList,
    // rootValue,// 这是自定义属性,就是实现schema相关的业务
    graphiql:true//是否启动调试界面
})));
app.listen(8888,()=>{
    console.log(`服务器运行在8888端口...`);
});

express版本
import express, { Express } from 'express';
import expressGraphql from 'express-graphql';
import SchemaList from './schema';//引入
const app: Express = express();
app.use(
    '/graphql',
    expressGraphql({
        schema: newsSchema,
        graphiql: true,
    })
);
app.listen(8888,()=>{
    console.log(`服务器运行在8888端口...`);
});
这样一个简单的GraphQL的后台实现就完成了,一套graphql代码可以同时在koa和express中使用,除了最后的配置不同之外
8.前端请求的实现
8.1 查询测试
        const _id = "5d399b76c2971845290e0237";
        //定义变量:$_id:类型 然后传入值
        //使用变量:_id:$_id
        const query = `query ($_id:String){
                            oneNews(_id:$_id){
                                _id,author,age,title,content,status
                            }
                        }`;
        //传入的数据data
        const data = {
            query,
            variables: {_id}
        }

        fetch("http://localhost:8888/graphql", {
            method: "POST",//最好post请求,当使用增删改的时候,get请求不支持
            headers: {//发送fetch请求,请求头需要带以下字段
                'Content-Type': "application/json",
                'Accept': "application/json"
            },
            body: JSON.stringify(data)
        }).then(res=>res.json()).then(data=>{
            console.log(data);//获取到结果
        });
oneNews里面的_id,author,age,title,content,status都是需要返回的字段,如只要_id,author,age,title,其它那些可以删掉,就是要什么接收什么
8.2增加测试
        //定义变量  $_id,$author,$age,$title,$content和对应的类型 然后传入值
        const query = `mutation ($author: String,$age: Int,$title:String,$content:String){
                        createNews(
                            author:$author,
                            age:$age,
                            title:$title,
                            content:$content){
                                    _id
                                    author
                                    age
                                    title
                                    content
                                    time
                                    status
                                }
                        }`;
        //传入的数据data
        const data = {
            query,
            variables: {
                author: "liuliuliu",
                age: 20,
                title: "标题党",
                content: "dsadsadsasd"
            }
        }

        fetch("http://localhost:8888/graphql", {
            method: "POST",
            headers: {
                'Content-Type': "application/json",
                'Accept': "application/json"
            },
            body: JSON.stringify(data)
        }).then(res => res.json()).then(data => {
            console.log(data);
        });
8.3删除修改操作也差不多如上的增加一样

如果需要在vue或者react中使用,则较为麻烦,需要安装依赖等,需要的小伙伴可以观看其它的博客学习如何在vue或者react中使用graphql

如果还需要看其它的可以点击本博主的头像
上一篇:poj2349 Arctic Network - 最小生成树


下一篇:Windows系统下使用Java实现Ping