首页 > 其他分享 >GraphQL的优势和开发模式

GraphQL的优势和开发模式

时间:2024-06-12 11:30:46浏览次数:13  
标签:请求 DataFetcher 模式 API GraphQL 优势 RESTful 我们

当下,前后端分离是互联网应用程序开发的主流做法,如何设计合理且高效的前后端交互Web API是前端和后台开发人员日常开发工作的一大难点和痛点。回想我们在日常开发过程中经常会碰到的几个场景:

  1. 后台开发人员调整了返回值的类型和数量而没有通知到前端
  2. 后台开发人员修改了某一个字段的名称没有通知到前端
  3. 前端开发人员需要通过多个接口的拼接才能获取页面暂时所需要的所有字段
  4. 前端开发人员无论想要多获取还是少获取目标字段都需要与后台开发人员进行协商

相信你对上面这个场景非常熟悉,因为我们每天都可能在反复经历着类似的场景。那么,如何解决这些问题呢?这就是今天我们要介绍的内容,我们将引入GraphQL这套全新的技术体系,它为我们解决上述问题提供了解决方案。

GraphQL的基本概念

相比REST,GraphQL可以说是一项比较新的技术体系,2012年诞生在Facebook内部,并于2015年正式开源。顾名思义,GraphQL是一种基于图(Graph)的查询语言(Query Language,QL),从根本上改变了前后端交互API的定义和实现方式。

要想使用GraphQL,我们首先需要关注它发送请求的方式。这里我们可以举一个例子。假设系统中存在一个获取用户信息的场景,那么一个典型的请求示例如下所示。

{

    user (id: "1") {

        name

        address

    }

}

可以看到基于GraphQL的请求方式与使用传统的RESTful API有很大的不同。除了在请求体中指定了目标User对象的参数id值之外,我们还额外指定了“name”和“address”这两个参数,也就是告诉服务器端这次请求所希望获取的数据字段。

显然,这种请求方式完美解决了前端无法预判响应的数据格式问题,因为前端在请求的同时已经知道从服务端返回的数据字段就是请求中指定的字段,因此前端就不需要再对响应结果进行专门的判断和处理。

针对传统交互方式中存在的多次请求问题,GraphQL可以把多次请求合并成一次。例如,我们可以发送这样一个请求。

{

    users {

       name

       address

       family{

          count

       }

    }

}

在该请求中,我们一方面指定了想要获取的User对象中的 “name”和“address” 字段,同时也指定了需要获取用户对应的家庭字段“family”以及它的子字段“count”。这样,通过一次请求,我们就可以同时获取用户信息和家庭信息,而不需要发送两次请求。

讲到这里,你可能已经注意到,通过GraphQL发起请求实际上只需要指定一个HTTP端点地址即可,因为我们可以基于同一个端点通过传入不同的参数而获取不同的结果,也就不需要专门设计一批HTTP端点来分别处理不同的请求了。

现在,我们已经了解了GraphQL的功能特性。那么,如何实施GraphQL呢?

GraphQL的实施方法

首先明确,我们并不推荐在任何场景下都使用GraphQL。对于那些API定义与资源概念匹配度较高、也不需要实现类似用户信息内部嵌套家庭成员信息的复杂查询场景,传统的RESTful API仍然是首选,各个HTTP端点之间相互独立,职责非常明确。但对有些场景而言,GraphQL则更有优势。包括:

  1. 业务复杂度高
  2. 需求变化快,以及
  3. 弱文档化管理

对于大多数系统而言,GraphQL的推行需要前后端进行紧密的配合,在这个配合过程中,前端的痛点往往是大于服务端的。所以,一般场景下前端对于引入GraphQL的述求要大于服务端。另一方面,如果采用和RESTful API一样的开发模式,那么实现GraphQL的工作量主要是在服务端。服务端同学需要基于GraphQL规范重新设计并实现API,通常都建议单独构建一个数据层来对外暴露GraphQL API。


  

在实施GraphQL的策略上,我们也可以总结几条最佳实践。首先,如果你已经实现了一部分RESTful 服务,那么可以让 GraphQL与这部分RESTful API并存发展。尤其是对于那些单一的RESTful服务,可以把GraphQL直接连接到已有的RESTful服务上。通过这种策略,RESTful服务中已经实现的业务逻辑层、数据访问层组件都可以得到复用,我们要做的只是开放一个新的GraphQL访问入口而已。而且,作为一项新技术的引入过程,GraphQL和RESTful服务在一段时间内并存发展也符合平滑过渡的客观需求。


如果你正在采用微服务架构,那么引入GraphQL的策略就可以是在所有后端微服务之前架设一层由GraphQL构建的数据层,并对后端服务提供的数据进行自由的组装之后开放给前端。这种实施策略类似于微服务架构中的API网关,一方面对前端请求进行适配和路由,一方面完成前后端之间的解耦。

GraphQL Java框架

我们知道,GraphQL是一种理念和规范,它并不直接提供开发工具和框架。而GraphQL Java是基于Java开发的一个GraphQL实现库,在实际的应用开发中,开发人员可以创建在自己的Controller层组件来与GraphQL完成整合。当然,我们也可以是对GraphQL Java进行一定的封装和扩展。因此,我们需要首先掌握GraphQL Java中所包含的核心编程组件。GraphQL Java中内置了一组核心的技术组件。


首先,我们需要引入一个核心组件,即Schema。所谓Schema,简单讲就是一种前后端交互的协议和规范,或者可以把它类比成RESTful API中的接口定义文档。在Schema中,开发人员需要指定两部分内容。一方面,我们需要明确定义前后端交互的数据结构,包括具体的字段名称、类型、是否为空等属性。另一方面,GraphQL规定每一个Schema中可以存在一个根Query和根Mutation,分别用于执行查询和更新操作。如下所示的就是一个典型的Schema定义。

type Query {

    employees: [Employee]

}

type Mutation {

    updateSalary(input: UpdateSalaryInput!): UpdateSalaryPayload

}

type Employee {

    id: ID!

    name: String

    salary: String

}

input UpdateSalaryInput {

    employeeId: ID!

    salary: String!

}

type UpdateSalaryPayload {

    success: Boolean!

    employee: Employee

}

在上述Schema中,我们看到了ID、String、Boolean等基本数据类型,以及用来表明是否为空的!和数组的[]。

第二个要介绍的组件是DataFetcher。从命名上看,DataFetcher组件的作用就是在执行查询时获取字段对应的数据。DataFetcher是一个接口,只定义了一个方法,如下所示。

public interface DataFetcher<T> {

    T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;

}

开发人员可以从DataFetchingEnvironment中获取传入的参数,并根据该参数来执行具体的数据查询操作。至于数据查询操作的具体实现过程,DataFetcher并不关心。

创建DataFetcher只是开始,我们还要将它们应用在GraphQL服务器上,这就需要借助RuntimeWiring组件。通过Runtime Wiring(运行时组装)机制,我们可以把DataFetcher整合在GraphQL的运行环境中。创建RuntimeWiring的典型代码如下所示。 

private UsersDataFetcher usersDataFetcher;

private UserDataFetcher userDataFetcher;

private ArticlesDataFetcher articlesDataFetcher;

private RuntimeWiring buildRuntimeWiring() {

    return RuntimeWiring.newRuntimeWiring()

        .type("Query", typeWiring -> typeWiring

             .dataFetcher("users", usersDataFetcher)

             .dataFetcher("user", userDataFetcher))

        .type("User", typeWiring -> typeWiring

             .dataFetcher("articles", articlesDataFetcher))

        .build();

}     

可以看到,这里通过RuntimeWiring的type方法将各个DataFetcher与对应的数据结构关联起来。

最后,基于Schema和RuntimeWiring,我们就可以创建GraphQL对象,如下所示。

File schemas = schemeResource.getFile();

TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemas);

RuntimeWiring wiring = buildRuntimeWiring();

GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);

GraphQL graphQL = GraphQL.newGraphQL(schema).build();

基于这个GraphQL对象,我们就可以使用它来完成具体的查询操作,最终面向业务层的代码如下所示。

String query = …;

ExecutionResult result = graphQL.execute(query);

可以看到,使用GraphQL Java进行开发的难度并不大,流程也比较固化。

在日常开发过程中,基于HTTP协议的RESTful API是我们目前主流的前后端开发模式,但并不一定是最合理的开发模式。今天我们所介绍的GraphQL具备的功能特性能够在一定程度上解决传统开发模式中所存在的一些问题。GraphQL更加具有灵活性和扩展性,并能显著减少前后端交互所需要的沟通和开发成本。在日常开发过程中,建议你根据自身业务发展的需求和变化,在合适的场景中引入GraphQL相关技术体系。

标签:请求,DataFetcher,模式,API,GraphQL,优势,RESTful,我们
From: https://blog.csdn.net/2401_83062316/article/details/139619618

相关文章

  • GPU开启持久化模式
    GPU开启持久化模式GPU驱动内存常驻模式,也称为GPU驱动持久模式。linux系统下,在persistence模式是enabled状态时,GPU驱动一直处于加载状态,减少运行程序时驱动加载的延迟。不开启该模式时,在程序每次调用完GPU后,GPU驱动都会被卸载,下次调用时再重新加载,驱动频繁卸载加载,......
  • 树莓派使用ethtool永久配置网口信息与工作模式
    1、安装ethtool软件使用指令sudoapt-getinstallethtool成功显示:pi@jcr:~$sudoapt-getinstallethtoolReadingpackagelists...DoneBuildingdependencytree...DoneReadingstateinformation...Doneethtoolisalreadythenewestversion(1:5.9-1).0upgr......
  • 专业的跨网软件,需要具备怎样的产品性能及优势?
    国家对数据安全要求和管理日益严格,要求规范化和标准化。像军工单位、科研院所、高科技企业、医疗医药、高新制造等单位,会涉及到核心保密数据。因此为了保护网络不受外部威胁和内部误操作的影响,通常会进行网络隔离,隔离成内网和外网。下面可以了解一些隔离方式:1.网闸/光闸隔离:阻断......
  • idm究竟有哪些优势
    IDM(InternetDownloadManager)作为一款功能强大的下载管理工具,在网络下载领域具有多个显著的优势。以下是IDM的主要优势,按照不同的功能点进行归纳和详细解释:加速下载速度:IDM能够智能地分割文件并同时使用多个下载线程,从而显著加快下载速度。这种多线程下载技术使得用户能......
  • 设计模式:从接口的角度切入静态工厂模式
    面向接口编程的意义所谓面向接口去编程的核心含义就是为了——“封装隔离”通常的封装,是指对数据结构的封装,将几种数据类型整到一块,组成一个新的数据类型;而java中的封装,包含对数据和行为进行抽象,然后定义出一个类,这个类即封装了数据和行为,但接口这里的封装,更多的是指对于行为......
  • Redis之哨兵模式
    概述无哨兵模式的主从切换的方法是当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵)架构来解决这个问题。哨兵模......
  • 测试对工厂模式的理解
    什么是工厂模式?请简要描述其核心目的。工厂模式是一种常用的设计模式,属于创建型模式的一种。它的核心目的是为了解决对象的创建过程与使用过程的分离,使得代码更加灵活、可维护,并降低模块间的耦合度。通过引入一个工厂类(或接口)来负责生产对象,客户端代码不再直接实例化具体对象,而......
  • 设计模式--1.0.2
    工厂模式Version1.0.2工厂模式提供一种创建对象的方式,而无需指定要创建的具体类。通过使用工厂模式,可以将对象的创建逻辑封装在一个工厂类中,而不是在客户端代码中直接实例化对象,这样可以提高代码的可维护性和扩展性。意图定义一个创建对象的接口,让其子类决定实例化哪一个具......
  • NAT-DDNS内网穿透技术,快解析DDNS的优势
    进行NAT穿透,是为了使具有某一个特定源IP地址和源端口号的数据包不被NAT设备屏蔽而正确路由到内网主机。对于穿透类型,一般分为两大类,一是基础NAT,另一个是NAPT,大家可能并不怎么了解。今天小编来为大家详细说一说内网穿透技术中基础NAT和NAPT,以及NAPT中对称型NAT和非对称型N......
  • 内网穿透的方式有哪些——快解析的优势
    外网穿透内网技术,即内网映射,是把目标本地内网地址和端口发布到互联网,是一种由内网开放到外网的权限操作。那么,内网穿透的方法有哪些呢?做映射外网的方法。需要结合自己本地网络环境和应用场景来实施。这里分享三种方法,只要是能上网的网络环境,都可以通过这三种方式实现内网穿透。......