www.129028.com:多少查询颗粒的小的采纳来讲,Gr

2019-10-06 18:25 来源:未知

我在如何使用Gatsby建立博客 / How to build a blog with Gatsby这篇文章中提过GraphQL在Gatsby中的应用。总的来讲,它是一个新潮的技术,在适宜的使用场景威力无穷。这里我们来讨论一下用/不用GraphQL的理由吧。

GraphQL

GraphQL按照官方的说法它是一门声明式的查询语言,实际上它是领域特定查询语 DSQL,它通过定义的schema系统将复杂的逻辑拆分成细粒度的数据结构,来让前端应用的开发者能够通过GraphQL提供的类型查询系统,自由定制请求数据的能力。

原文:Top 5 Reasons to Use GraphQL

www.129028.com 1GrahQL

GraphQL与RESTful

目前大多数应用的API采用的都是流行的RESTful API,但是对于很多需求变更频繁的,数据查询颗粒的小的应用来说,使用RESTful的API总是在不断的迭代,不断的更新版本。这会导致应用的API系统过于复杂,而且通常最后又大量冗余的API进而变动难以维护。

“The REST interface is designed to be efficient for large-grain hypermedia data transfer…” - Dr Roy T Fielding, Author of REST

其实REST本身更适合数据力度大,需求变更不频繁的应用场景,而在细粒度的应用场景下的解决方案,在Facebook的复杂系统中应运而生,GraphQL被用于解决细粒度的API问题已经3年多了,处理了260多亿次的请求,这注意证明它在真实的场景下是经得起考验的。

整个GraphQL的核心就是一个类型定义系统,通过定义各种可能的查询类型和所有的返回数据的类型,来构建一个查询系统,让客户端通过统一的查询语言,来对系统中的类型进行匹配,并最终返回,相匹配的数据。

GraphQL 由以下组件构成:

  • 类型系统(Type System)
  • 查询语言(Query Language)
  • 执行语义(Execution Semantics)
  • 静态验证(Static Validation)
  • 类型检查(Type Introspection)

目的

GraphQL已成为新的API开发标准。

为何仅用两年多时间,GraphQL就已走在了API开发的前沿?为何开发人员喜欢GraphQL快速开发?本文给出几个理由。

www.129028.com 2

GraphQL是Facebook2015年开源的数据查询规范。现今的绝大多数Web Service都是RESTful的,也就是说,client和server的主要沟通模式还是靠client根据自己的需要向server的若干个endpoint 发起请求。由于功能的日渐丰富,对Web Application的要求变得复杂,REST的一些问题逐渐暴露,人们开始思考如何应对这些问题。GraphQL便是具有代表性的一种。GraphQL这个名字,Graph

类型

GraphQL中类型系统是最重要的组成部分之一,其中提供的类型分为两种,一种是标量类型,用于表示最细粒度的类型,这些类型基本可以和JavaScript,Ruby及其他通用编程语言对应上。
标量类型:

  • Int : 整数,对应 JavaScript 的Number
  • Float :浮点数,对应 JavaScript 的 Number
  • Boolean:布尔值,对应 JavaScript 的 Boolean
  • String : 字符串,对应 JavaScript 的 String
  • ID : D 值,是一个序列化后值唯一的字符串,可以视作对应 ES 2015 新增的 Symbol

其他的高级类型:

  • Object : 对象类型 ,用于表示GraphQL返回类型树的中间层级,标量类型表示的都是叶子节点,在GraphQL基本上所以的类型都是Object类型,它包含有一个name字段来描述定义的类型和fields字段描述该类型的完整数据结构。
var AddressType = new GraphQLObjectType({
    name: 'Address',
    fields: {
      street: { type: GraphQLString },
      number: { type: GraphQLInt },
      formatted: {
        type: GraphQLString,
        resolve(obj) {
          return obj.number + ' ' + obj.street
        }
      }
    }
});
  • Interface : 接口类型 用于描述多个类型中通用的字段
var EntityType = new GraphQLInterfaceType({
    name: 'Entity',
    fields: {
      name: { type: GraphQLString }
    }
});
  • Union : 联合 它有点像可选类型,用于表示这一个字段可能是一个类型集合下的某一种类型。
var PetType = new GraphQLUnionType({
    name: 'Pet',
    types: [DogType, CatType],
    resolveType(value) {
      if (value instanceof Dog) {
        return DogType;
      }
      if (value instanceof Cat) {
        return CatType;
      }
    }
});
  • Enum :枚举类型
var RGBType = new GraphQLEnumType({
    name: 'RGB',
    values: { 
      RED: { value: 0 },
      GREEN: { value: 1 },
      BLUE: { value: 2 } 
    }
});
  • List : 列表类型
var PersonType = new GraphQLObjectType({
   name: 'Person',
    fields: () => ({
      parents: { type: new GraphQLList(Person) },
      children: { type: new GraphQLList(Person) },
    })
});
  • Non-Null : 不为空类型,用于表示返回的字段不为空,如果为空就会发生异常,可用于数据库的主键。
var RowType = new GraphQLObjectType({
    name: 'Row',
    fields: () => ({
      id: { type: new GraphQLNonNull(GraphQLString) }
    })
});

1) GraphQL API 有强类型 schema

对大多数API而言,最大的问题在于缺少强类型约束。常见场景为,后端API更新了,但文档没跟上,你没法知道新的API是干什么的,怎么用,这应该是前后端掐架的原因之一。

GraphQL schema 是每个GraphQL API的基础,它清晰的定义了每个API支持的操作,包括输入的参数和返回的内容。

GraphQL schema是一个约定,用于指明API的功能。

GraphQL schema是强类型的,可使用SDL(GraphQL Schema Definition Language)来定义。相对而言,强类型系统使开发人员自行车换摩托。比如,可以使用构建工具验证API请求,编译时检查API调用可能发生的错误,甚至可以在代码编辑器中自动完成API操作。

schema带来的另一个好处是,不用再去编写API文档——因为根据schema自动生成了,这改变了API开发的玩法。

  • Query Language,就表明了它的设计初衷是想要用类似图的方式表示数据:即不像在REST中,数据被各个API endpoint所分割,而是有关联和层次结构的被组织在一起。

查询

GraphQL的客户端,是通过一个查询字符串通过,GraphQL服务可以解析验证并执行这样的查询请求字符串,一个查询字符串有两部分组成:操作(Operation)和片段(Fragments) 一个 query 可以包含多个操作和片段。只有包含操作的 query 才会被 GraphQL 服务执行。但是不包含操作,只有片段的 query 也会被 GraphQL 服务解析验证,这样一份片段就可以在多个 query 文档内使用。

GraphQL 规范支持两种操作:

let schema = new GraphQLSchema({ query: UserType mutation: UpdateAgeType});
  • query:仅获取数据(fetch)的只读请求
query {
    user(id: 3500401) {
      id,
      name,
      age
    }
}
  • mutation:获取数据后还有写操作的请求
mutation {
    updateAage
}

其中GraphQL对数据的修改称为mutation ,它在GraphQL的查询系统中是按照顺序序列化执行的。

查询请求模型:

www.129028.com 3

2) 按需获取

我们经常谈GraphQL的主要优点——前端可以从API获取想要的数据,不必依赖REST端返回的固定数据结构。

如此,解决了传统REST API的两个典型问题:Overfetching和Underfetching。

使用GraphQL,前端自己决定返回的数据及结构。

比方说,假设这么一个提供user信息的REST API: <server>/users/<id>,和提供用户的关注者的API:<server>/users/<id>/followers,以及该用户关注对象的API: <server>/users/<id>/followed-users。传统的REST会需要3次API call才能请求出这三份信息(假设<server>/users/<id> 没有包含followers and followed-users信息,which will be a definite redundancy if it does):1 GET <server>/users/<id>

总结

GraphQL在技术上提供了区别于REST的解决方案,很好的解决了数据细粒度频繁变更的问题,使得数据和接口得到了解绑,在生态圈方便面,现已经有很多语言的GraphQL实现(Python 、Ruby 等)可以参见 GraphQL Awesome list。在应用方面虽然是2015年才被Facebook公布并且开源的,但是它已经在Facebook的应用系统中工作了快四年之久。而且现在不少国内的团队(比如淘宝)也已经在使用GraphQL构建应用系统的API,这些都足以证明这项技术的市场和潜力了。

Overfetching

Overfetching意味着前端得到了实际不需要的数据,这可能会造成性能和带宽浪费。

栗子:个人资料页面需要呈现用户姓名和生日;提供用户信息的API(如/users/id)还会返回用户的地址和账单信息,但这在个人资料页面没有用,也没必要。

{ "user": { "id" : "u3k2k3k178", "name" : "graph_ql_activist", "email" : "graph_ql@activist.com", "avatar" : "img-url" }}

Underfetching

Underfetching与Overfetching想反,API返回中缺少足够的数据,这意味着前端需要请求额外的API得到需要的数据。

最坏的场景下,不足的结果会导致臭名昭著的N+1请求问题:获取数据列表,而没有API能够满足列表字段要求,不得不对每行数据发起一次请求,以获取所需数据。

栗子:假设我们在捣鼓一个博客应用。显示 user列表,除user本身信息外,还要显示每个user最近一篇文章的title。然而,调用/users/仅得到user集合,不得不对每个user调用/users/<id>/articles获取其最新文章。

说明:当然你可以再写一个API来满足特殊场景,如/users/lastarticles/来满足上面的需求,但需要编写后端相关代码,调试和部署,加班....有这时间何不去陪家人孩子。

2 GET <server>/users/<id>/followed-users3 GET <server>/users/<id>/followers

3) GraphQL支持快速产品开发

GraphQL使前端开发人员轻松,感谢GraphQL的前端库(Apollo、Relay或Urql),前端可以用如缓存、实时更新UI等功能。

前端开发人员生产力提高,产品开发速度加快,无论UI如何变后端不用变。

构建GraphQL API的过程大多围绕GraphQL scheme。由此,经常听到 schema-driven development(SDD),这只是指一个过程,功能在schema中定义,在resolver(解析器)中实现。

www.129028.com:多少查询颗粒的小的采纳来讲,GraphQL就已走在了API开荒的前方。有了像GraphQL Faker这样的工具,前端开发可以在schema定义后开始。GraphQL Faker模拟整个GraphQL API(依赖于定义的schema),因此前后端可以独立工作。

然而如果使用GraphQL,一次API请求即可获取所有信息并且只选取需要的信息(比如关于用户只需要name不要email, followers只要最前面的5个name,followed-users只要头像等等):

4) Composing GraphQL API

schema拼接(stitching)是GraphQL中的新概念之一,简而言之,可以组合和连接多个GraphQL API,合并为一个。与React组件概念类似,一个GraphQL API可以由多个GraphQL API构成。

这对前端开发非常有用,不然,需要与多个GraphQL端点通信(通常在微服务架构或与第三方API集成时)。由于schema拼接,前端只需要处理单个API端点,而协调与各种服务通信的复杂性从前端隐藏。

query { user (id : "u3k2k3k178") { name followers  { name } followed-users { avatar } }}

5) 丰富的开源生态和牛逼闪闪的社区

自Facebook正式发布GraphQL以来,仅两年多时间,整个GraphQL生态系统的成熟程度难以置信。

刚发布时,开发人员使用GraphQL的唯一工具是graphql-js参考实现——一个Express.js中间件和GraphQL client Relay。

现在,GraphQL规范的参考实现有多种语言可以选择,并有大量的GraphQL客户端。此外许多工具提供了无缝的工作流程,并在构建GraphQL API时提供爽爽的开发体验,如:Primsa、GraphQL Faker、GraphQL Playground、graphql-config等。

GraphQL社区日益壮大,越来越多的公司将其用之于产品。

www.129028.com 4

我们会得到一个完全按照query定制的,不多不少的返回结果(一般是一个json对象)。

参考

  • GraphQL 中文文档
  • How to build a GraphQL Server with graphql-yoga
  • How to GraphQL: The fullstack GraphQL tutorial
  • GraphQL boilerplates: Starter kits for GraphQL projects with Node, TypeScript, React, Vue,…

使用GraphQL的理由, 必然是从讨论RESTful Service的局限性和问题开始。

  1. 数据冗余和请求冗余 (overfetching & underfetching)
  2. 灵活而强类型的schema
  3. 接口校验 (validation)
  4. 接口变动,维护与文档
  5. 开发效率

根据users API的例子,我们可以想见,GET用户信息的REST call,我们就算只是想要一个用户的一两条信息(比如name & avatar),通过该API,我们也会得到他的整个信息。所谓的overfetching就是指的这种情况——请求包含当前不需要的信息。这种浪费会一定程度地整体影响performance,毕竟更多的信息会占用带宽和占用资源来处理。

同样从上面的例子我们可以看出来,在许多情况下,如果我们使用RESTful Application,我们常常会需要为联系紧密并总量不大的信息,对server进行多次请求,call复数个API。

举一个例子,获取ID为"abc1"和"abc2"的两个用户的信息,我们可能都需要两个API call,一百个用户就是一百个GET call,这是不是很莫名其妙呢?这种情况其实就是underfetching——API的response没有合理的包含足够信息。

然而在GraphQL,我们只需要非常简单地改变schema的处理方式,就可以用一个GET call解决:

query { user (ids : ["ab1", "abc2", ...])}

我们新打开一个网页,如果是RESTful Application,可能请求数据就会马上有成百上千的HTTP Request,然而GraphQL的Application则可能只需要一两个,这相当于把复杂性和heavy lifting交给了server端和cache层,而不是资源有限,并且speed-sensitive的client端。

GraphQL是强类型的。也就是说,我们在定义schema时,类似于使用SQL,是显式地为每一个域定义类型的,比如说:

type User { id: ID! name: String! joinedAt: DateTime! profileViews: Int! @default}type Query { user: User}

GraphQL的schema的写作语言,其实还有一个专门的名称——Schema Definition Language 。

这件事情的一大好处是,在编译或者说build这个Application时,我们就可以检查并应对很多mis-typed的问题,而不需要等到runtime。同时,这样的写作方式,也为开发者提供了巨大的便利。比如说使用YAML来定义API时,编写本身就是十分麻烦的——可能没有理想的auto-complete,语法或者语义有错无法及时发现,文档也需要自己小心翼翼地编写。就算有许多工具(比如Swagger)帮助,这仍然是一个很令人头疼的问题。

TAG标签:
版权声明:本文由www.129028.com-澳门金沙唯一官网www129028com发布于编程新闻,转载请注明出处:www.129028.com:多少查询颗粒的小的采纳来讲,Gr