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