本文由智能化研发管理工具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 | GraphQLNonNull;
输入类型(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(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
- JSON(使用 GZIP 压缩)
GraphQL 服务通常返回 JSON 格式的数据,但 GraphQL 规范 并未要求这一点。对于期望更好的网络性能的 API 层来说,使用 JSON 似乎是一个奇怪的选择,但由于它主要是文本,因而在 GZIP 压缩后表现非常好
- 版本控制
虽然没有什么可以阻止 GraphQL 服务像任何其他 REST API 一样进行版本控制,但 GraphQL 强烈认为可以通过 GraphQL schema 的持续演进来避免版本控制
- 分页
- 服务器端的批处理与缓存
两种数据请求方式
-
Queries
-
Mutations
示例代码地址
graphql-koa-demo
资料
GraphQL 规范 spec.graphql.cn/
GraphQL 中文文档 graphql.cn/
对于前端不同框架也都有关于Graphql相关的库
- angular
- vue
网站文档: vue-apollo.netlify.app/
- react