GraphQL的认识与使用
前言
GraphQL已经被越来越多的开源项目作为业务接口的开发规范,而在此之前流行的是restful接口。那么GraphQL是什么?GraphQL相比restful有哪些好处?本文带你初窥GraphQL的门道,看看你们的业务是否适合使用GraphQL。
GraphQL是什么
GraphQL = Graph + QL (query language)
GraphQL是一种图表化(graph)的查询语言(query language),用于定义API的查询语法。GraphQL只定义api查询语法和数据规范,没有限制前端和后端的类型,也没有限制存储层的实现。
可以类比SQL,SQL仅定义了一套数据操作与查询语言的规范,Mysql,oracle等各大数据库开放了符合SQL标准的接口,当然你可以自己开发一个使用SQL查询的业务接口。
官网解释:
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data
GraphQL既是一种用于API的查询语言也是一个满足你数据查询的运行时。
GraphQL的组成结构
1. schema
GraphQL通过schema定义api和数据结构,schema通常以文件形式存在,包含一系列的对象定义。对象结构为类json格式的字符串。
根据总结,对象定义的格式遵守以下规则:
${对象类型} ${对象名称} {#字段${字段名称}: ${字段类型}#字段类型为数组${字段名称}: [${字段类型}]#字段类型为非空对象${字段名称}: ${字段类型}!#带参数的字段${字段名称} (${对象名称} : ${对象类型}): ${字段类型}
}
GraphQL定义了一些标量类型,可作为对象的字段定义。标量类型有:Int、Float、String、Boolean、ID。
其中ID类型是GraphQL定义的唯一标识符,其本质上也是字符串。
GraphQL支持枚举类型enum,枚举类型定义示意:
enum Gender {malefemale
}
GraphQL的对象类型主要分为两类,数据对象和接口对象,分别用于定义接口的输入输出和接口实体。
数据对象
- type
自定义名称的类型(关键字除外),用于定义接口查询的返回对象类型以及内联对象类型。
type Man {name: Stringage: Intgender: Gender
}
- interface
接口类型interface,和type对象定义基本一致。
interface Human {name: Stringage: Intgender: Gender
}
对象可以通过implements申明实现了某个接口对象,实现对象必须包含接口对象的所有字段,方便对相同业务属性进行抽象。
type Man implements Human {name: Stringage: Intgender: Gender
}
- input
输入类型input本质上也是一个type类型,是作为Mutation接口的输入参数。换言之,想要定义一个修改接口(add,update,delete)的输入参数对象,就必须定义一个input输入类型。
input ManInput {name: Stringage: Intgender: Gender
}
值得一提的是,在input对象中的对象也必须是input类型,这可能是一个比较局限的设计。
接口对象
接口对象分为数据查询(select)接口和数据操作(add,update,delete)接口,分别用Query关键字和Mutation关键字来定义。下面举两个例子:
定义一个名为search的查询接口,返回对象为Human类型:
type Query {search(name: String): Human
}
定义一个名为add的数据插入方法,方法参数为Human类型,返回对象也为Human类型:
type Mutation {add(human: Human): Human
}
Mutation类型不对数据的操作含义进行区分,不像SQL一样,有ADD、UPDATE、DELETE,统一使用Mutation进行定义,具体的操作含义在接口的实现中完成。
2. query
通过schema对api进行定义之后,后续发起的graphql api请求都必须严格遵守这个定义。特别的,在graphql的api请求中可以指定返回对象的部分而非全部的字段,从而减少一些不必要的数据传输。
GraphQL的api请求只有Query和Mutation两种,下面简单介绍下Query和Mutation的查询语法。
简单query语句
//调用search接口,传入一个名为name的字符串参数,期望的返回类型是Human对象中的age字段
query {search(name: "马云"): {age}
}
带参数的graphql api请求附带一个专门用于描述请求参数json数据,json的key和api参数名称对应。
带对象参数的query语句
//调用search接口,传入一个名为human的Human对象参数,期望的返回值是Human对象中的age字段
query queryHuman($human: Human) {search(human: $human): {age}
}//graphql的参数,以json格式给出,对应类型Human
graphql variables
{"human": {"name": "马云"}
}
带对象参数的Mutation语句
//调用add接口,传入一个名为human的Human对象参数,期望的返回值是human对象的三个字段
mutation addHuman($human: Human) {add(human: $human): {nameagegender}
}//graphql的参数,以json格式给出,对象的结构和schema定义必须一致
graphql variables{"human": {"name": "马云","age": 50,"gender": "male"}
}
3. datafetchers
datafetcher其实是graphql-java中的一个组件,其作用是查询和操作业务数据,并提供api的返回值。datafetcher会通过显式的申明和query绑定起来,从而实现api和数据层的交互。
任何一门语言实现graphql都需要类似datafetcher这样一个组件来实现api和数据层的交互。
GraphQL能带来什么好处?
使用GraphQL能带来什么好处呢?我总结主要有以下几点:
- 强一致性
graphql的协议规定了api和schema的定义必须保持一致,这种文档先行的开发模式,使得项目的架构更加清晰,并且使得接口本身就多了一层校验。
- 减少数据冗余
graphql的api在请求时可以指定返回的字段,返回的字段和预期是一致的。这一特性可以让接口在不同的场景下返回必需的字段,减少部分网络开销,并且使得接口的通用性更高。
- 自文档性
得益于graphql的强一致性,使得graphql的schema本身就可以作为api接口文档使用。配合graphql的一些第三方库,可以做到api文档的在线调试和可视化展示,变成真正的图化(graph)查询语言(query language)。
graphiql插件的在线调试api功能
graphql voyager的图形化api查看
GraphQL有什么缺点?
来说说我认为graphql的主要缺点吧:
- 简单问题复杂化
为了实现graphql充分的规范性,也加重了一些开发成本(虽然已经有第三方库可以做到快速开发),任何一个api在开发时都有明确的两步走:1.在schema定义接口和对象 2.实现datafecher,哪怕是一个最简单的get请求。
- 不方便统一控制
graphql不像restful接口,有清晰的层级划分(/a/b/c的结构),graphql的api只能使用接口名称进行区分,接口名称不像层级结构那么容易管理。通常在restful结构下,我们可以通过拦截器对符合某一规则的接口路径进行统一处理(比如对/restful/*的接口进行身份认证),而graphql的请求路径是在同一个url下的,这种处理逻辑就比较难以实现了。
GraphQL框架支持
- graphql-js
graphql官方的js实现,可以快速的搭建js端的graphql服务器,和进行graphql请求。
官方文档地址:
https://graphql.cn/graphql-js/
- graphql-java
graphql官方的java实现,前文也介绍过了,是基于datafetcher的架构,代码比较容易理解,缺点是开发量较大。
官方文档地址:
https://www.graphql-java.com/documentation/v16/
使用graphql java开发graphql接口的demo
public static void main(String[] args) {//1. 定义schema,这里是字符串直接给出了schemaString schema = "type Query{hello: String}";SchemaParser schemaParser = new SchemaParser();TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);//2. 定义datafetcher,并和query进行绑定;这里的datafetcher会返回一个固定值worldRuntimeWiring runtimeWiring = newRuntimeWiring().type("Query", builder ->builder.dataFetcher("hello", new StaticDataFetcher("world"))).build();SchemaGenerator schemaGenerator = new SchemaGenerator();GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();//3. 查询时指定查询名hello,不带任何参数,也不指定返回值ExecutionResult executionResult = build.execute("{hello}");System.out.println(executionResult.getData().toString());// Prints: {hello=world}
}
- graphql-kick-start
第三方实现的一个开源graphql java库,优点是能快速接入,配合springboot开发,几乎不需要写代码,并且集成了很多方便的插件如 graphiql,graphql voyager,可以实现真正的图化查询。
官方github地址:
https://github.com/graphql-java-kickstart/graphql-spring-boot
使用graphql-kick-start的graphql servlet插件快速开发graphql接口的demo
#启用 graphql servlet
graphql.servlet.enabled=true
#graphql servlet 使用的url
graphql.servlet.mapping=/graphql
#schema文件路径
graphql.tools.schema-location-pattern=person.schema
person.schematype Query {personByName(name: String): Person
}type Person {id: Intname: String
}
//GraphQLQueryResolver的实现类中的方法会自动和schema中的query绑定
@Component
public class PostQuery implements GraphQLQueryResolver {public Person personByName(String name) {PersonEntity personEntity = personMapper.findByName(name);return new Person(personEntity);}
}
GraphQL的用途
基于graphql的种种特性,以及graphql的库支持的程度来看(似乎官方也认定graphql是用于前后端接口开发的,并未提供除了js之外的客户端实现),目前而言,graphql似乎只适用于前后端之间的接口开发。所幸的是,graphql和restful并不冲突,前端接口可以直接剥离出来,使用graphql规范重新实现,且不影响原有接口。
综上所述,graphql主要用于实现前后端之间的接口,且有graphql本身的强一致性带来了很多规范上的优势。
GraphQL的认识与使用相关推荐
- 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能
相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制 完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询 自APIJSON发 ...
- 【译】GraphQL vs. REST
原文地址:GraphQL vs. REST 原文作者:Sashko Stubailo 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:wilsonandus ...
- fcm和firebase_我如何最终使Netlify Functions,Firebase和GraphQL一起工作
fcm和firebase In a previous post I confessed defeat in attempting to get an AWS Lambda GraphQL server ...
- 如何使用FaunaDB + GraphQL
I have one or two projects I maintain on Netlify, in addition to hosting my blog there. It's an easy ...
- 我希望支持JavaScript GraphQL实现的API
The GraphQL schema language is great! It is certainly the best way to communicate anything about a G ...
- graphql是什么_为什么GraphQL是避免技术债务的关键
graphql是什么 GraphQL (not to be confused with GraphDB or Open Graph or even an actual graph) is a rema ...
- graphql_普通英语GraphQL指南
graphql by Luis Aguilar 路易斯·阿吉拉尔(Luis Aguilar) 普通英语GraphQL指南 (A Guide to GraphQL in Plain English) 您 ...
- react 错误边界_React with GraphQL和错误边界中的自定义错误页面
react 错误边界 by Abi Noda 通过Abi Noda React with GraphQL和错误边界中的自定义错误页面 (Custom error pages in React with ...
- java通用象棋游戏_在通用国际象棋界面周围模拟GraphQL包装器
java通用象棋游戏 The Universal Chess Interface (UCI) has been around a long time and used by many chess en ...
- graphql redux_如何在Redux应用程序中使用GraphQL
graphql redux by Howon Song 通过宋颂恩 如何在Redux应用程序中使用GraphQL (How to use GraphQL in your Redux app) Fetc ...
最新文章
- 基于TF-IDF编码进行文本聚类分析:文档成对相似性计算、层次聚类(链接矩阵、树形图dendrogram绘制、聚类标签)
- 深入理解$watch ,$apply 和 $digest --- 理解数据绑定过程——续
- VS VC 读取 INI文件
- JAVA标识符命名规则及命名规范
- java写入carbondata_Carbondata使用过程中遇到的几个问题及解决办法
- java UTD对点发送信息_Java微信公众平台开发(九)--关键字回复以及客服接口实现(该公众号暂时无法提供服务解决方案)...
- vue打包运行并解决404问题
- 一台电脑有线连接路由器另一台无线连接_两个无线路由器怎么实现无线桥接【详细介绍】...
- 数据库学习一站式入门资料(纯干货)
- java 创建txt_JAVA读取TXT文件、新建TXT文件、写入TXT文件
- Android WIFI的管理方法
- Android储物柜代码,Android的应用程式储物柜安全性如何? | MOS86
- POI实现 Excel插入图片
- 内网服务器反弹映射到公网ip去访问
- ORA-01654: unable to extend index报错解决
- 最佳情侣身高差c语言函数,“最佳情侣身高差是多少为妙?”哈哈哈,神评尤为突出啊...
- 像李欣频一样思考人生~
- 自然几何之分形(2)
- 江淮500后桥壳体机械加工工艺及精镗两侧面孔工序夹具设计
- open_files打开输入输出文件
热门文章
- 中国信息安全测评中心-自主原创测评
- wps怎么把字缩到最小_WPS文字如何调节字体大小突破字号72的限制实现大小随意调...
- 2017第九届广州国际园林机械与园艺工具展 2017第九届广州国际园林景观与美好人居博览会 第九届广州国际花卉盆栽及花店花园用品展览会 2017中国花卉展览会 第九届广州国际绿化苗木展会刊(参展商名录
- 量子计算与区块链抗量子算法
- 次世代游戏建模制作工作流程 1
- 防止用户调整微信浏览器字体大小导致的显示异常
- 动态规划--01背包问题详解
- insert()用法
- uni-app z-index无效的解决办法(遮罩层)
- Python学习笔记:通过Headers字段模拟浏览器访问亚马逊界面爬取