写点什么

GraphQL 入门指南

发布于: 3 小时前
GraphQL 入门指南

本文由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/learn/serving-over-http/

  • JSON(使用 GZIP 压缩)

GraphQL 服务通常返回 JSON 格式的数据,但 GraphQL 规范 并未要求这一点。对于期望更好的网络性能的 API 层来说,使用 JSON 似乎是一个奇怪的选择,但由于它主要是文本,因而在 GZIP 压缩后表现非常好

  • 版本控制

虽然没有什么可以阻止 GraphQL 服务像任何其他 REST API 一样进行版本控制,但 GraphQL 强烈认为可以通过 GraphQL schema 的持续演进来避免版本控制

  • 分页

https://graphql.bootcss.com/learn/pagination/

  • 服务器端的批处理与缓存

https://graphql.bootcss.com/learn/caching/

两种数据请求方式

  • Queries

  • Mutations





示例代码地址

graphql-koa-demo

资料

GraphQL 规范 https://spec.graphql.cn/

GraphQL 中文文档 https://graphql.cn/

对于前端不同框架也都有关于 Graphql 相关的库

  • angular

官网: https://www.apollographql.com/

库: https://github.com/kamilkisiela/apollo-angular

  • vue

网站文档: https://vue-apollo.netlify.app/

库: https://github.com/Akryum/vue-apollo

  • react

库: https://github.com/apollographql/react-apollo

发布于: 3 小时前阅读数: 9
用户头像

还未添加个人签名 2021.02.01 加入

还未添加个人简介

评论

发布
暂无评论
GraphQL 入门指南