GraphQL是一种API查询语言,是数据查询的运行时。它不同于传统的Restful方法。后端返回的数据可以由前端控制。GraphQL历史GraphQL核心知识GraphQL小练习原文地址,欢迎Star和订阅我的博客。GraphQL的历史由来已久,包括现在,大部分接口还是采用RestFul的接口方式,非常符合我们的思路。RestFul通过将界面划分为不同的controller、action等对界面进行归纳,通过制定一套标准的界面返回格式来规范前后端之间的交互。我们仔细想想。其实RestFul更多的是通过前后端的“约定”来管理接口。如果程序员不遵守这个约定怎么办?可能会出现问题,常见问题分为以下几类:数据获取过多和数据获取不足接口太多难以管理接口返回值不符合规范一个页面需要调用多个接口获取所有的数据。我相信你会经常遇到它。虽然处理起来很简单,但是沟通成本太高了。如果前端只是发现某个字段名不对,需要后端配合修改发布来解决。好在GraphQL看到了RestFul的痛点,专注于接口查询,并制定了一套自己的接口规范,让客户端可以根据自己的需要定制需要返回的数据。举个简单的例子,我们发送一个get请求,只要提供query参数,就可以根据提供的参数获取对应的数据格式。//requestheaderquery{person(personId:7){name,age}}//response//{//name:'lmjben',//age:26//}GraphQL核心知识GraphQL中最重要的概念是Schema,Schema表示接口的类型,即前后端接口的一种约定。这个约定通常写在一个单独的文件中,即.graphql文件。Schema定义好后,前后端会严格按照Schema进行请求和响应。例如:如果我们的数据库中有一张student表,我们可以定义一个对象类型来表示这张表中的字段。此外,我们还可以扩展一些方法(根据学生的成绩来判断学生是否优秀)。此外,GraphQL还包括以下类型。#内置标量类型:Int、Float、String、Boolean、ID#自定义标量类型typeStudent{name:Stringage:Intsex:BooleanisGood(grade):Boolean}#自定义标量类型typePhoto{url:Stringsize:Inttype:PhotoTypepostedBy:Student}#enumerationtypeenumPhotoType{SELFLEACTION}#querytypetypeQuery{allStudents:[Student]allPhotos:[Photo]}#changetypetypeMutation{postPhoto(input:PostPhotoInput):Photo}#InputtypeinputPostPhotoInput{url:String}#SubscriptiontypetypeSubscription{newPhoto:PhotonewStudent:Student}上面的类型中,还有3个比较重要的类型,它们分别是:Query,Mutation,Subscrition,只有它们可以用作为每个GraphQL查询的入口(即get请求携带的参数)。Query查询就是查询的意思,也可以支持嵌套。例如:我们发送allPhotos查询所有照片,嵌套一层postedBy查询找到照片的上传者。query{allPhotos{urlpostedBy{name}}}后端收到客户端的请求后,使用对应的Resolver返回所有对应的照片,然后根据postedBy中存储的学生id找到对应的学生信息,然后收益一起返回,对应的配置如下。conststudents=[];constphotos=[];constresolver={Query:{allPhotos:()=>{returnphotos;}},照片:{postedBy:photo=>{returnstudents.find(item=>item.id===photo.postedBy);}}};除了强大的查询系统,MutationGraphQL还提供了Mutation变化。其实就是告诉服务器你要修改数据,类似于RestFul中的put。比如上传一张图片,返回上传图片的尺寸,需要发送如下header。mutation{postPhoto(url:'https://baidu.com/default.png'){url,size}}如果上传多个参数,需要拼接很多字符串操作。变异为我们提供了一种简单的方法。即通过匹配输入类型,传递参数更方便。例如:上传数据时只在querybody中发送占位符,将上传的内容单独放在variables字段中。mutationpostPhoto($input:PostPhotoInput){postPhoto(url:$input.url){url,size}}//参数单独存储//http://xx.com/graphql?variables={input:{url:"https://baidu.com/defaul.png"}}SubscritionSubscrition和其他类型类似,不同的是它表示订阅,即如果查询内容定义在Subscrition中,则前面的一个双向连接后端通过webSocket建立数据通道,每当数据发生变化时,可以自动推送到客户端。例如:上面我们定义了Subscrition类型,然后我们定义了一个action类型的photo,当插入一个新的action类型的photo时,会通知其他query去刷新数据。subscription{newPhoto(type:'ACTION'){urlsize}}对应的Resolver配置如下。constresolver={Mutation:{postPhoto:async(parent,args,{pubsub})=>{//触发更新pubsub.publish("photo-add");}},Subscription:{newPhoto:{//监听photo-add事件,实时推送订阅给客户端:(parent,args,{pubsub})=>{returnpubsub.asyncIterator("photo-add");}}}};使用Apollo和Express构建一个GraphQL服务器。步骤如下:定义GraphQL类型使用Apollo启动一个服务写一个处理GraphQL类型的方法:Resolver先定义GraphQL类型前端和后端。这种类型是并行开发的,互不影响。#自定义标量类型typeStudent{name:Stringage:Intsex:Booleangrade:IntisGood:Boolean}#自定义标量类型typePhoto{url:Stringsize:Inttype:PhotoTypepostedBy:Student}#枚举类型enumPhotoType{SELFLE#SelfietypeACTION#Actiontype}#QuerytypetypeQuery{allStudents(id:Int):[Student]allPhotos:[Photo]}#ChangetypetypeMutation{postPhoto(input:PostPhotoInput):Photo}#InputTypeinputPostPhotoInput{url:String}#订阅类型typeSubscription{newPhoto:Photo}启动一个GraphQL服务接下来我们启动一个支持GraphQL的Web服务。我们使用apollo-server-express非常方便的创建一个graphql环境。constexpress=require("快递");const{ApolloServer,PubSub}=require("apollo-server-express");constserver=newApolloServer();constapp=express();server.applyMiddleware({app});httpServer.listen({port:4000},()=>console.log(`服务器在http://localhost:4000${server.graphqlPath}`));编写Resolver处理GraphQL类型,然后编写Resolver处理GraphQL类型对应的业务逻辑,返回对应类型的数据。const学生=[];constphotos=[];//匹配处理方法constresolvers={query:{//第一个参数是父查询集,因为可能嵌套调用//第二个参数是查询集参数//第三个参数是ApolloServer初始化时注入的对象allStudents:(parent,args,yy)=>{returnstudents;},allPhotos:()=>{返回照片;}},Mutation:{//第一个参数是父查询集,因为可能是嵌套调用//第二个参数是查询集传递的参数//第三个参数是ApolloServer初始化时注入的对象postPhoto:(parent,args,{pubsub})=>{returnphotos[0];}},学生:{isGood:parent=>{returnparent.grade>90;}},照片:{postedBy:photo=>{returnstudents.find(item=>item.id===photo.postedBy);}}};consttypeDefs=fs.readFileSync("./typeDefs.graphql",{encoding:"utf-8"});constserver=newApolloServer({typeDefs,//我们定义的类型文件解析器//类型对应的处理方法});写完这三步,我们的GraphQLApi就完成了,是不是很简单。完整代码:GitHub链接PS:欢迎订阅我的博客,一起努力吧~
