乐趣区

关于graphql: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/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…

退出移动版