本文由智能化研发管理工具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 自带一组默认标量类型:

  1. Int:有符号 32 位整数。
  2. Float:有符号双精度浮点值。
  3. String:UTF‐8 字符序列。
  4. Boolean:true 或者 false。
  5. 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

库: https://github.com/apollograp...