GraphQL 入门指南

·  阅读 243
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 | 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(id:ID!,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

graphql.bootcss.com/learn/servi…

  • JSON(使用 GZIP 压缩)

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

  • 版本控制

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

  • 分页

graphql.bootcss.com/learn/pagin…

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

graphql.bootcss.com/learn/cachi…

两种数据请求方式

  • Queries

  • Mutations

image.png

示例代码地址

graphql-koa-demo

资料

GraphQL 规范 spec.graphql.cn/

GraphQL 中文文档 graphql.cn/

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

  • angular

官网: www.apollographql.com/

库: github.com/kamilkisiel…

  • vue

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

库: github.com/Akryum/vue-…

  • react

库: github.com/apollograph…

分类:
代码人生
标签:
收藏成功!
已添加到「」, 点击更改