• GraphQL基础篇


            最近参与了一个大型项目,大型项目随着系统业务量的增大,不同的应用和系统共同使用着许多的服务接口API,而随着业务的变化和发展,不同的应用对相同资源的不同使用方法最终会导致需要维护的服务API数量呈现爆炸式的增长。而另一方面,创建一个大而全的通用性接口又非常不利于移动端使用(流量损耗),而且后端数据的无意义聚合也对整个系统带来了很大的资源浪费。

           1、 GrapQL背景 

           经查资料显示GraphQL是Facebook 在2012年开发的,2015年开源,2016年下半年Facebook宣布可以在生产环境使用,而其内部早就已经广泛应用了,用于替代 REST API。Facebook的解决方案:用一个“聪明”的节点来进行复杂的查询,将数据按照客户端的要求传回去,后端根据GraphQL机制提供一个具有强大功能的接口,用以满足前端数据的个性化需求,既保证了多样性,又控制了接口数量。

            2、 使用介绍

           GraphQL并不是一门程序语言或者框架,它是描述请求数据的一种规范,是协议而非存储,GraphQL本身并不直接提供后端存储的能力,它不绑定任何的数据库或者存储引擎,它可以利用已有的代码和技术来进行数据源管理。

           一个GraphQL查询是一个被发往服务端的字符串,该查询在服务端被解释和执行后返回JSON数据给客户端。作为服务端除了了解具体的生态之外还需要了解缓存、上传文件等,如果是系统迁移还需要了解特定的框架,作为系统开发推荐使用Prisma的框架。偏向客户端方向的话,需要进一步了解关于graphql-client的相关知识,推荐使用apollo。

           3、 优缺点

            GraphQL虽然能够代替广泛使用的REST API,但也是各有千秋。

            3.1优点: 

            RESTful服务端决定有哪些数据获取方式,客户端只能挑选使用,如果数据过于冗余也只能默默接收再对数据进行处理;而数据不能满足需求则需要请求更多的接口。 
            GraphQL给客户端自主选择数据内容的能力,客户端完全自主决定获取信息的内容,服务端负责精确的返回目标数据。提供一种更严格、可扩展、可维护的数据查询方式。

            3.2缺点:

            重构:使用GraphQL对数据源进行管理,相当于要对整个服务端进行一次换血,考虑的不仅仅是需要针对现有数据源建立一套GraphQL的类型系统,同时需要改造服务端暴露数据的方式,这对业务久远的产品无疑是一场灾难。

           查询性能:GraphQL查询的每个字段如果都有自己的resolve方法,可能导致一次查询操作对数据库跑了大量的query。

           4、 Type类型

           在GraphQL中,我们通过预先定义一张Schema和声明一些Type来达到预期的效果, 

           首先我们需要知道:

    • 对于数据模型的抽象是通过Type来描述的
    • 对于接口获取数据的逻辑是通过Schema来描述的

           GraphQL的Type简单可以分为两种,一种叫做Scalar Type(标量类型),另一种叫做Object Type(对象类型)。

           注意:标量是GraphQL类型系统的最小颗粒。

           4.1标量类型

           GraphQL中的内建的标量包含String、Int、Float、Boolean、Enum。也可以通过Scalar声明一个新的标量:

           a、 Prisma中,还有DateTime和ID这两个标量分别代表日期格式和主键。(prisma一个使用GraphQL来抽象数据库操作的库)

           b、 Upload标量来代表要上传的文件

          4.2高级数据类型

          复杂的数据模型:Object、Interface、Union、Enum、Input Object、List、Non-Null(Object、Interface 和 Union 三种类型是不能作为输入对象类型的)。       

          总之,我们通过对象模型来构建GraphQL中关于一个数据模型的形状,同时还可以声明各个模型之间的内在关联(一对多、一对一或多对多)。

           4.3类型修饰符

           当前的类型修饰符有两种,分别是List和Required ,它们的语法分别为[Type]和Type!, 同时这两者可以互相组合,比如[Type]!或者[Type!]或者[Type!]!(请仔细看这里!的位置),它们的含义分别为:

    • 列表本身为必填项,但其内部元素可以为空
    • 列表本身可以为空,但是其内部元素为必填
    • 列表本身和内部元素均为必填

            5、 Schema逻辑

            我们其实不妨把它当做REST架构中每个独立资源的URL来理解它,只不过在GraphQL中,我们用Query来描述资源的获取方式。因此,我们可以将Schema理解为多个Query组成的一张表。

           5.1 定义Query类型

           GraphQL中使用Query来抽象数据的查询逻辑,当前标准下,有三种查询类型,分别是query(查询)、mutation(更改)和subscription(订阅),这三种查询类型必须是Root Query(根查询)存在的。

           注:Query特指GraphQL中的逻辑查询(包含三种类型),query指GraphQL中的查询类型(仅指查询类型)对于传统的CRUD项目使用query(查询)、mutation(更改)就够了,subscription(订阅)是针对real-time应用提出。

           5.2 Resolver解析函数

           Schema中声明了若干Query,那么我们只进行了一半的工作,因为我们并没有提供相关Query所返回数据的逻辑。在GraphQL中,我们会有这样一个约定,Query和与之对应的Resolver是同名的,这样在GraphQL才能把它们对应起来。大体的解析流程就是遇到一个Query之后,尝试使用它的Resolver取值,之后再对返回值进行解析,这个过程是递归的,直到所解析Field的类型是Scalar Type(标量类型)为止。 

           Resolver本身的声明在各个语言中是不一样的,因为它代表数据获取的具体逻辑。它的函数签名(以js为例子)如下:function(parent, args, ctx, info) {}

    其中的参数的意义如下:

           parent: 当前上一个Resolver的返回值

           args: 传入某个Query中的函数(比如上面例子中article(id: Int)中的id)

           ctx: 在Resolver解析链中不断传递的中间变量(类似中间件架构中的context)

           info: 当前Query的AST对象

           注意:Resolver内部实现对于GraphQL完全是黑盒状态。这意味着Resolver如何返回数据、返回什么样的数据、从哪返回数据,完全取决于Resolver本身,基于这一点,在实际中,很多人往往把GraphQL作为一个中间层来使用,数据的获取通过Resolver来封装,内部数据获取的实现可能基于RPC、REST、WS、SQL等多种不同的方式。

           好了,GraphOL基础今天我就总结在这里,关于其实战应用且等下回分晓。

  • 相关阅读:
    java执行构造器和初始化字段的顺序
    java语言中的varargs
    对Java语言的byte类型变量进行无符号提升
    VisualStudio 切换帐号 (原帐号已过期且无法登录时用)
    C/C++ 的关系运算符采用短路运算
    实现std::string的ltrim、rtrim和trim方法
    Excel 用于批量把单元格设置为"文本格式保存的数字"的宏
    为什么要用webUI?
    CEF3中js调用delphi内部方法
    2016-1-1最新版本的linphone-android在mac上编译通过,同时建立了IDEA工程
  • 原文地址:https://www.cnblogs.com/yiliukejich0614-1234/p/10778492.html
Copyright © 2020-2023  润新知