本文由智能化研发管理工具PingCode技术经理 龚林杰分享
什么是 GraphQL
A query language for your APIs
GraphQL 是一种由 Facebook 提出的用于 API 的查询语言,也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余
常用的API有哪些
什么是API
API 全称:Application programming interface, API的本质就是读数据、写数据。
我们常用的API分成两个流派
- 基于REST(Representational State Transfer)
REST:表现层状态转移,是一种软件架构风格,而不是一个标准。REST 用 HTTP 封装,走的是 HTTP 协议。那么给予 REST 有哪些衍生品?RESTFUL: 操作资源 ,GraphQL: A query language for your APIs
- 基于RPC
用自定义的协议 http, http2, 消息队列(redis), tcp 等封装的一套远程调用的API,很典型的一个技术就是gRPC.
为什么要使用GraphQL
REST API 存在的问题以及怎么应对
- POST / PUT / DELETE 傻傻分不清楚,有时候界限模糊
- 由于是操作资源路由有时候会很长,如 /work-items/:id/comments/:cid/like
- 数据返回冗余,叫 Overfetching
- 数据返回缺少一些字段,叫 Underfetching
- 接口数据如何兼容不同平台
我们在使用REST接口时,接口返回的数据格式、数据类型都是后端预先定义好的,如果返回的数据格式并不是调用者所期望的,作为前端的我们可以通过以下两种方式来解决问题:
- 和后端沟通,改接口(更改数据源)
- 自己做一些适配工作(处理数据源)
- 后端专门为其他平台(移动端)提供接口
GraphQL 的优势在哪
借助 GraphQL,组织内的不同客户端应用程序可以轻松地仅查询所需数据,这一点超越了其它 REST 方法,并带来了实际应用程序性能的提高。使用传统的 REST API 端点,客户端应用程序将详询服务器资源,并接受包含了与请求匹配的所有数据的响应。如果来自 REST API 端点的成功响应返回 35 个字段,那么客户端应用程序就会收到 35 个字段。
- GraphQL API 有强类型 schema
- 按需获取
- GraphQL支持快速产品开发
- Composing GraphQL API
- 丰富的开源生态和社区
GraphQL 的概念和示例
Schema 和 类型 (Schemas and Types)
- 类型系统(Type System)
GraphQL 查询语言基本上就是关于选择对象上的字段
因为一个 GraphQL 查询的结构和结果非常相似,因此即便不知道服务器的情况,你也能预测查询会返回什么结果。但是一个关于我们所需要的数据的确切描述依然很有意义,我们能选择什么字段?服务器会返回哪种对象?这些对象下有哪些字段可用?这便是引入 schema 的原因。
每一个 GraphQL 服务都会定义一套类型,用以描述你可能从那个服务查询到的数据。每当查询到来,服务器就会根据 schema 验证并执行查询。
query {
blogPosts {
title
}
}
- 类型语言(Type Language)
GraphQL 服务可以用任何语言编写,因为我们并不依赖于任何特定语言的句法句式来与GraphQL schema 沟通。我们定义了自己的简单语言,称之为 “GraphQL schema language” —— 它和 GraphQL 的查询语言很相似,让我们能够和 GraphQL schema 之间可以无语言差异地沟通
- 对象类型和字段(Object Types and Fields)
一个 GraphQL schema 中的最基本的组件是对象类型,它就表示你可以从服务上获取到什么类型的对象,以及这个对象有什么字段。使用 GraphQL schema language,我们可以这样表示它
- 参数(Arguments)
- 查询和变更类型(The Query and Mutation Types)
schema {
query: Query
mutation: Mutation
}
- 标量类型(Scalar Types)
一个对象类型有自己的名字和字段,而某些时候,这些字段必然会解析到具体数据。这就是标量类型的来源
GraphQL 自带一组默认标量类型:
Int
:有符号 32 位整数。Float
:有符号双精度浮点值。String
:UTF‐8 字符序列。Boolean
:true 或者 false。ID
:ID 标量类型表示一个唯一标识符
- 枚举类型(Enumeration Types)
enum BlogType {
TECH
NEWS
...
}
- 列表和非空(Lists and Non-Null)
对象类型、标量以及枚举是 GraphQL 中你唯一可以定义的类型种类。但是当你在 schema 的其他部分使用这些类型时,或者在你的查询变量声明处使用时,你可以给它们应用额外的类型修饰符来影响这些值的验证
myField: [String!]
query BlogPostWithComment($id: ID!) {
blogPost(id: $id) {
title
... on BlogPost {
description
}
}
}
- 接口(Interfaces)
跟许多类型系统一样,GraphQL 支持接口。一个接口是一个抽象类型,它包含某些字段,而对象类型必须包含这些字段,才能算实现了这个接口
- 联合类型(Union Types)
export type GraphQLType =
| GraphQLScalarType
| GraphQLObjectType
| GraphQLInterfaceType
| GraphQLUnionType
| GraphQLEnumType
| GraphQLInputObjectType
| GraphQLList<any>
| GraphQLNonNull<any>;
- 输入类型(Input Types)
export default new GraphQLInputObjectType({
name: "BlogPostInput",
fields: {
_id: { type: GraphQLID },
title: { type: GraphQLString },
description: { type: GraphQLString },
},
});
查询和变更 (Queries and Mutations)
- 字段(Fields)
简单而言,GraphQL 是关于请求对象上的特定字段
query {
blogPosts {
title
}
}
{
"data": {
"blogPosts": [
"title": "R2-D2"
]
}
}
- 参数(Arguments)
query {
blogPosts(id: "xxx") {
_id
title
}
}
{
"data": {
"blogPosts": [
"_id": "xxx"
"title": "R2-D2"
]
}
}
- 别名(Aliases)
query {
blogs: blogPosts(id: "xxx") {
title
}
}
{
"data": {
"blogs": [
"_id": "xxx"
"title": "R2-D2"
]
}
}
- 片段(Fragments)
GraphQL可复用单元,可以避免重复代码
query {
one: blogPost(id: "59507b70729885c9097720fc") {
...commonFields
}
two: blogPost(id: "59507b8b729885c9097720fe") {
...commonFields
_id
description
}
}
fragment commonFields on BlogPost {
title
}
- 操作名称(Operation name)
query BlogPostOperationName {
blogPosts {
title
description
}
}
- 变量(Variables)
query BlogPostOperationName($id: ID = "59507b70729885c9097720fc") {
blogPost(id: $id) {
title
}
}
- 指令(Directives)
query BlogPostOperationName($id: ID!, $withDescription: Boolean!) {
blogPost(id: $id) {
title
description @include(if: $withDescription)
}
}
variables {
"id": "59507b70729885c9097720fc",
"withDescription": false
}
- 变更(Mutations)
mutation {
addBlogPost (data: {title: "abcdefg", description: "abcdefg"}) {
title
description
}
}
- 内联片段(Inline Fragments)
query BlogPostWithComment($id: ID!) {
blogPost(id: $id) {
title
... on BlogPost {
description
}
}
}
验证 (Validation)
通过使用类型系统,你可以预判一个查询是否有效。这让服务器和客户端可以在无效查询创建时就有效地通知开发者,而不用依赖运行时检查。
执行 (Execution)
一个 GraphQL 查询在被验证后,GraphQL 服务器会将之执行,并返回与请求的结构相对应的结果,该结果通常会是 JSON 的格式
GraphQL 不能脱离类型系统处理查询
内省 (Introspection)
我们有时候会需要去问 GraphQL Schema 它支持哪些查询。GraphQL 通过内省系统让我们可以做到这点
{
__schema {
types {
name
}
}
}
{
__schema {
queryType {
name
}
}
}
GraphQL 最佳实践
GraphQL 规范特意忽略了一些面向 API 的重要问题,例如处理网络、授权和分页。这并不意味着在使用 GraphQL 时没有针对这些问题的解决方案,只是因为它们并非 GraphQL 定义中的一部分,可代以工程上通行的做法来实现。
- HTTP
https://graphql.bootcss.com/l...
- JSON(使用 GZIP 压缩)
GraphQL 服务通常返回 JSON 格式的数据,但 GraphQL 规范 并未要求这一点。对于期望更好的网络性能的 API 层来说,使用 JSON 似乎是一个奇怪的选择,但由于它主要是文本,因而在 GZIP 压缩后表现非常好
- 版本控制
虽然没有什么可以阻止 GraphQL 服务像任何其他 REST API 一样进行版本控制,但 GraphQL 强烈认为可以通过 GraphQL schema 的持续演进来避免版本控制
- 分页
https://graphql.bootcss.com/l...
- 服务器端的批处理与缓存
https://graphql.bootcss.com/l...
两种数据请求方式
- Queries
- Mutations
示例代码地址
graphql-koa-demo
资料
GraphQL 规范 https://spec.graphql.cn/
GraphQL 中文文档 https://graphql.cn/
对于前端不同框架也都有关于Graphql相关的库
- angular
官网: https://www.apollographql.com/
库: https://github.com/kamilkisie...
- vue
网站文档: https://vue-apollo.netlify.app/
库: https://github.com/Akryum/vue...
- react
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。