将 REST 包装为 GraphQL

小夏 科技 更新 2024-02-01

从前端开发人员的角度来看,GraphQL 是一个数据层范式,它支持乐观更新、React 组件旁边的声明性数据获取和所见即所得数据。 它由 Facebook 推广,它提供的不仅仅是 RESTful API。 本文附带一个来自生产环境的示例,展示了如何在不影响后端开发人员的情况下将现有的 RESTful API 包装到前端 GraphQL API 中。

在我从外包商那里接手的一个前端项目中,我看到了很多有趣的遗物,比如在页面之间复制和粘贴的无用导入,以及许多带有 .bak 但是一个与另一个页面没有太大区别的旧页面,孩子般的组件命名等。 API 的使用尤其令人印象深刻,如下所示:

import * as mapi from '../../lib/mapi';// ..省略不相关的** componentwillmount() mapipie() then(json => )mapi.whoami() then(json => )
它看起来有点臃肿,因为里面有很多重复**。

这看起来有点令人困惑,因为我们看不到 piedata 中的内容。 如果你有更深的层次,很容易脱身cannot read property 'machine' of undefinedundefined is not an object,尤其是当您还使用 ES6 计算属性值时,调试时间会变得有点长。

还有很多其他问题,例如必须对 UI 中的数据进行非 null 检查。

这里的问题是,我们将数据置于一种状态,该状态在 null 时不提供类型检查和默认值,例如 props。

虽然使用 Redux 这样的数据流框架可以解决大部分问题,但由于现在是重构的时候了,重要的是让这个重构迭代尽可能长地存在——解决干扰开发人员理解的大问题。 我最感兴趣的是数据对我的可见性:

我希望在编写 UI 时能够看到数据的样子,最好数据看起来与我的 UI 结构完全一样,这样将数据绑定到 UI 的过程就变得简单愉快了。 」

现状是,每次绑定数据都要用邮递员请求后端看看返回的数据是什么样子的,然后调用这个API,并从返回的数据中取出一些我需要的数据绑定到UI上,很弱三千取一勺。由于业务变化,我必须同时在一个 UI 组件中使用多个 API。

我喜欢在常用词中将字母大写,例如:deviceid,而后端叔叔喜欢小写,例如dviceid。哦,我的上帝,他在拼写时错过了一个 e!

理想情况下,后端应该快速跟进业务更改,拆分 API,然后翻阅婴儿名称列表,为每个 API 提供一个新的有意义的名称。 但显然后端不会放下手头的很多东西来配合你改造API,毕竟数据为什么要跟着UI长一张脸,你觉得你的UI很帅吗? 此外,如果三天后需求再次发生变化怎么办? 让后端再次重写其余的端点,他会用他的皮大衣鞭打你。

同时使用 Redux 和 GraphQL 可以解决这些问题。

过去在REST中,我们根据业务将数据划分为不同的路径,相当于根据第一个版本的业务需求,给每一堆数据一个当时容易理解的名称,然后希望以后每个业务都使用一个

古代外包人员的方法export function whoami() export function pie() export function entry() export function districtpie(id) pie );export function siteoverview(id) /overview`);export function sitepie(id) /pie`);export function cabinetsswitches(id) /cabinets/switches`);export function sitewarningquantity(id) `
在 GraphQL 中,我们将数据表示为一棵树,并且可以直接请求它的任何叶子。

与REST类似,我们也可以有易于理解的名称,但是我们可以直接观察更小粒度的数据,而不是幻想路径中隐藏了哪些数据,如下所示:

重构的 API 帐户 WhoamiType UserType API 信息条目 API 数据站点概述 战区信息,指示地球上有哪些据点或子战区,并且战区有自己的**比例饼图数据 它还可以表示据点的数据,其中可以包括比例饼图和运输线列表等数据 类型 PowerentityType
我们可以在注释中看到每个数据类型与原始REST端点之间的关系,一个数据类型可以从多个原始RESTful数据源拼凑而成(例如集成多个微服务),或者一个REST数据源可以根据常识重组成多个数据类型,这样三个月后重读时就可以理解了。

这种转换有两个直接的好处:首先,您可以直接看到数据源的样子! 不再有邮递员请求抓取数据,因为你不记得每个数据终结点上有哪些字段可用。 二是它提供了静态类型检查,所以你可以在写类型的时候考虑每个类型应该是什么样子,然后把检查数据可用性的工作放在一边,专注于业务......

还有两个间接的好处:一个是她写得好像在写 FlowType 或者 TypeScript,你现在正在给数据添加类型注解,几个月后你开始学习 Rust 的时候,你会有宾至如归的感觉,你可以在 21 分钟内从初学者变成精通。 第二个是可以对数据端点进行标注,可以使用?? 黑色问号运算符声明性地表达你对业务的困惑,也可以与 ! 划船运算符描述数据项的不可或缺性。

我们上面用来声明类型的语言叫做 GraphQL,GitHub 正在将他们的 API 迁移到 GraphQL,所以你可以检查它是如何编写的。 它通常以模式编写js 文件,如下所示:

export const typedefinitions = `schema # ..省略其他类型的声明
它写在多行文本第一行内的第一行上,以便更容易查看调试的行号。 让我们将其导出为常量类型定义。

写完数据类型声明后,我们还需要写架构JS 继续解释如何获取这些数据类型中的每一种以及它们对应的数据。 我们使用分析函数来做到这一点:

// schema.jsexport const resolvers = , args, context) ,username(, args, context) ,password(, args, context) ,token(, args, context) ,id(, args, context) ,name(, args, context) ,companyid(, args, context) ,companyname(, args, context) ,departmentid(, args, context) ,departmentname(, args, context) ,role(, args, context) ,// ..省略其他分析功能,**以实物为准};
正如我们所看到的,我们实际上为每个我们可能需要的字段提供了一个函数作为数据源,当我们在 UI 中需要几个字段时,我们发出的请求会在这里触发一些函数,从而只返回我们需要的字段对应的数据,然后数据会被类型检查并返回到我们发出请求的 UI。

这可能就是在 UI 中使用它的感觉:

function mapstatetoprops(state) ;const mainpagedata = gql` query mainpagedata($token: string!) const queryconfig = ) => ( 我们配置 GraphQL hoc 在其 props pollinterval: 10000, }props: (=> (connect(mapstatetoprops) Redux classic usage@graphql(MainPageData, QueryConfig) graphql hocexport 默认类 main extends 组件;  static defaultprops = , render()
事实上,graphql 数据端点也是 schemajs 中的数据类型,以及解析函数,应该是后端叔叔写的。 不过,后台大叔有家庭,有自己的生活,你不应该为了你更开心亲自写UI而要求他放弃生活中的很多美好事物,我们不能这么残忍。

更好的方法是插入一个简单的 GraphQL 数据端点作为 UI 层和数据层之间的中介。

在这个中介中,我们可以将原本一次性返回一大块数据的 API 拆分为细粒度的数据类型,可以纠正后端返回的数据中的错别字,可以检查数据是否为空,我们来看一个例子:

// rest2graphqlinterface.以下大部分都是js中的例程,你只需要修改部分模型导入apolloclient,从'apollo-client';import from 'graphql';import from 'lodash';import from './schemagenerator';import from './schema';import from './models';修改此部分 import houtaidashuconnector from'./houtaidashuconnector';const typedefs = [.rootschema];const resolvers = merge(rootresolvers);const executableschema = makeexecutableschema();const serverconnector = new houtaidashuconnector();const rest2graphqlinterface = ),其中你引入了自己的连接器 },graphqlrequestvariables );const client = new apolloclient();export default client;
然后将 Redux 提供程序替换为仅限 GraphQL 成员的 ApolloProvider:

从。

成为。

这样一来,获取数据的链就大致串在一起了,你会发现数据是这样的:

舅舅后端的 RESTful API ->连接器 ->模型 ->解析器函数 -ExecutableSchema ->rest2graphqlinterface ->ApolloClient ->redux -> UI 的道具 -> UI

正如我们之前所看到的,当我们创建rest2graphqlinterface时,我们写道:

user: new user(),
其中 user 是模型。

为什么会这样写?

其实所有的数据采集,也就是请求给后台大叔的RESTful API,我们可以把它放在分析函数里,但是我们会写很多重复的**,而且每一点数据我们就要抓一次,这是浪费资源,一个弱水三千拿一勺喝的概念。

因此,我们抽象出一层模型:

// models.jsexport class user ) async getloginstatus(token) catch (error) async getallmetadata(token) getmetadata(field, token) }
如果我们希望模型专注于数据缓存和数据清理,我们必须将网络请求的部分抽象为连接器:

export default class houtaidashuconnector token=$`;return promise.try(()=> fetch(`$/$$`then(checkstatus) .then(response => response.json())then(json => return json.data; }
这样一来,我们就可以通过切换连接器,轻松切换我们是连接到内网设置的测试服务器,还是连接到外网的生产服务器,而不会影响模型和架构中的逻辑(当然,其实还是会受到影响的,因为你连接了测试服务器进行更新**以适应最新的业务)。

从那里,我们在客户端设置了一个轻量级的 GraphQL 服务器,作为我们和后端之间的中介。 基于进程内测试,这对性能没有明显影响,良好的缓存逻辑甚至可以加快页面加载速度。

使用此技术后,数据的采集不会写入componentwillmount()它不是隐藏在 redux reducer 中,不是隐藏在 redux-saga 生成器中,而是真正深入草根,就在我们的 UI 旁边,爱房子和黑,一石二鸟,所见即所得,腰部柔软易推。

这种客户端-graphql-server的方式也非常适合控制物联网设备,毕竟在物联网设备中设置server-side-graphql-server是不切实际的,使用RESTful API编写物联网控制会比较臃肿,在客户端将这些数据转换为graphql是一种可行的方法。

如果您对内容有任何疑问,可以添加China GraphQL用户组302490951进行交流。 比如有个同志看到我之前写过关于接力的教程,就问我接力好不好,我什么都知道:不好用,所以现在改用apollostack

wrapping a rest api in graphql apollo-client issue #

相似文章

    REST和RPC有什么区别?

    分布式系统之间的通信方式对其效率 可靠性和整体功能至关重要。REST 具象状态传输 和RPC 远程过程调用 是众所周知的通信范式。REST 和 RPC 允许不同的系统或组件相互通信。然而,它们在理念 设计和应用方面有着根本的不同。本教程重点介绍 REST 和 RPC 之间的区别,揭示它们的历史 原理...

    “暖冬,包冬包饺”。

    包饺子 是我国冬至期间许多地方的传统习,到了月,冬至节的步伐也在慢慢推进。让精神上感受到相同的文化氛围是实现健康目标的重要组成部分。为了让人们与不同的社会群体取得联系,增强与他人交往的自信心,进一步促进人们融入社会,在崇州市民政局的指导下,在崇州市精神障碍社区指导中心的支持下,月日,白头镇抚远站与 ...

    我奶奶家包饺子,爷爷因为家太穷而把我打出去

    六七岁那年,家里忙着种地,父母吃饭不了,有一次我和叔叔的弟弟在外面玩,最后玩累了,饿了,就和弟弟商量去奶奶家吃饭。到了奶奶家,看到奶奶在包饺子,我和弟弟坐在那里看奶奶包饺子,催奶奶赶紧包饺子,我们都饿死了。奶奶茫然地看了我一眼,说,你是饿鬼转世!整天,我不干活,想吃饭回你家吃饭,家里不欠你吃饭。被奶...

    “神音”把阿音当成免费的血袋?凝水兽的治疗技术将被逆转

    神音 中的仙魔之战,让整个三界都吃尽了苦头,魂兽一族也遭到了毁灭性的打击,其中凝水兽更是惨不忍睹。仙魔之战,导致了魂兽种族的濒临灭绝,凝水兽的珍贵存在也受到了影响,整个兽族只剩下几个蛋,阿音的诞生沾染了风音的吉祥之光,可惜她有 却没有看到妹妹孵化成功。凝水兽之所以备受推崇,是因为它们蕴含着强大的 能...

    沈音把阿音当成免费的血袋?凝水兽的治疗技术将被逆转

    成像能力计划 仙魔之战,三界可以说是吃了不少苦头,甚至还有不少魂兽被消灭了,凝水兽就是最好的例子,他们的孵化之旅更加艰难,还遭遇了仙魔大战,最终整个兽族被毁灭到只有两个蛋,阿音的出生沾染了凤音的光芒,可惜她已经 很久了,一直没有看到姐姐孵化成功。凝水兽之所以珍贵,是因为他们体内的能力最强,不管是神还...