2025上半年,最新 AI实践都在这!20+ 应用案例,任听一场议题就值回票价 了解详情
写点什么

超越 REST

  • 2021-03-31
  • 本文字数:4140 字

    阅读完需:约 14 分钟

超越 REST

娱乐业一直在努力应对 COVID-19 对全球制作的影响冲击。自 2020 年初以来,Netflix 一直在迭代开发系统,以向内部利益相关方和企业领导者提供有关疫情最新信息的最新工具和仪表盘。这些软件解决方案使得管理层可以就给定的实体产品是否以及何时能够安全地开始在全球范围内创建引人注目的内容而做出最明智的决策。在 Netflix Studio Engineering 内部,一种备受关注的方法是将 GraphQL 微服务(GQLMS)作为后端平台来促进应用程序的快速开发。


许多组织都在拥抱 GraphQL,以其作为统一企业范围内数据模型的一种方式,并提供了一个用其相关实体网络来导航大量结构化数据的单一入口点。这种努力值得称赞,但往往需要内部组织之间历经几个季度的协调,然后将所有相关实体开发并集成到一个单一的单体图中。


与“用一张图来管理所有对象”的方法不同,GQLMS 只是利用 GraphQL 来作为构建 CRUD 应用程序的丰富 API 规范。我们使用 GQLMS 进行了快速的概念验证应用,其经验证实了 GraphQL 宣传其好处时所提出两个理论:


  • GraphiQLIDE 在模式(schema)旁边显示任何可用的 GraphQL 文档,从而极大地改善了 API 使用者的人机工程学(与同类中最好的 Swagger UI 相比)

  • GraphQL 的强类型系统和多语言客户端支持,意味着 API 提供者无需关心特定于语言的 API 客户端的生成、版本控制和维护(比如,那些使用优秀的 Swagger Codegen 生成的客户端)。GraphQL API 的使用者可以简单地利用自己喜欢的开源 GraphQL 客户端。



GraphiQL:为 《星球大战》API 自动生成的测试 GUI


我们的经验已经为对 GQLMS 作为快速开发平台感兴趣的团队带来了一个具有许多最佳实践的架构。


Graphile


在早期的 GraphQL 探索过程中,Netflix 的工程师意识到 Graphile 库可以将 PostgreSQL 数据库对象(表、视图和函数)作为 GraphQL API 来呈现。Graphile 支持 智能注解,支持通过使用特定格式的 PostgreSQL 注解标记数据库的表、视图、列和类型来控制各种特性。文档甚至可以嵌入到数据库注解中,以便在 Graphile 生成的 GraphQL 模式中显示。


我们假设有一个 Docker 容器,其上运行了一个带有 Graphile 库的非常简单的 NodeJS Web 服务器(以及一些用于安全、日志、度量和监控的 Netflix 内部组件),可以为快速开发工作提供“比 REST 更好的 REST”或“REST++”平台。使用 Docker,我们定义了一个轻量级的独立容器,它允许我们将 Graphile 库及其支持的代码打包成一个独立的包,任何团队都可以在 Netflix 上使用它,而无需额外的编码。只需下拉定义 Docker 的基础镜像,并使用适当的数据库连接符运行它即可。这种方法被证明是非常成功的,并且对 Graphile 的使用产生了一些深刻洞察。


具体来说:


  • 使用数据库视图作为“API 层”来保持灵活性,以允许在不变更现有 GraphQL 模式(构建在数据库视图上)的情况下修改表。

  • 使用 PostgreSQL 聚合函数 时,请使用 PostgreSQL 复合类型。

  • 通过允许 GraphQL 客户端“所用权限”(“full access”)自动生成的 GraphQL 查询和 Graphile 生成的突变(在所有表和视图上公开的 CRUD 操作)来提高灵活性;然后在开发过程的后期,删除在应用程序投产之前未被 UI 使用到的模式元素。

数据库视图作为 API


我们决定将数据表放在一个 PostgreSQL 模式中,然后在另一个模式中定义这些表的视图,同时 Graphile Web 应用程序使用专用的 PostgreSQL 用户角色连接到数据库。这最终能实现几个不同的目标:


  • 可以独立于 GraphQL 模式中公开的视图来更改底层表。

  • 视图可以进行基本的格式化(比如将 TIMESTAMP 字段呈现为 ISO8601 字符串)。

  • 底层表上的所有权限必须显式地授权给 Web 应用程序的 PostgreSQL 用户,以避免意外的写操作。

  • 表和视图可以在同一个事务中进行修改,这样就可以原子地对公开的 GraphQL 模式进行更改。


关于最后一点:更改表中列的类型将会打破关联的视图,但是通过封装在事务中的更改,可以删除视图、更新该列,然后可以在提交事务之前重新创建视图。我们在启用 pgWatch 的情况下运行 Graphile,只要对数据库做任何更新,GraphQL 模式就会立即更新以反映所做的更改。

PostgreSQL 复合类型


Graphile 在读取 PostgreSQL 数据库模式以及将表和基本视图转换为 GraphQL 模式方面做得非常出色,但我们的经验表明,当视图中存在 PostgreSQL 聚合函数 或 JSON 函数 时,Graphile 在如何描述嵌套类型方面存在局限性。原生 PostgreSQL 函数,比如json_build_object,将被转换成 GraphQLJSON类型,该类型只是一个String,没有任何内部结构。例如,以这个返回JSON对象的简单视图为例:


postgres_test_db=# create view postgraphile.json_object_example as  select json_build_object(‘hello world’::text, 1, ‘2’::text, 3)  as json;postgres_test_db=# select * from postgraphile.json_object_example;          json— — — — — — — — — — — — -{“hello world”: 1, “2”: 3}(1 row)
复制代码


在生成的模式中,数据类型为JSON



json字段的内部结构(hello world2这两个子字段)在生成的 GraphQL 模式中是不透明的。


为了进一步描述json字段的内部结构(将其在生成的模式中公开),定义一个复合类型,并创建一个返回该类型的视图:


postgres_test_db=# CREATE TYPE postgraphile.custom_type AS (  "hello world" integer,  "2" integer);
复制代码


接下来,创建一个返回该类型的函数:


postgres_test_db=# CREATE FUNCTION postgraphile.custom_type(  "hello world" integer,  "2" integer)RETURNS postgraphile.custom_typeAS 'select $1, $2'LANGUAGE SQL;
复制代码


最后,创建一个返回该类型的视图:


postgres_test_db=# create view postgraphile.json_object_example2 as  select postgraphile.custom_type(1, 3)  as json;postgres_test_db=# select * from postgraphile.json_object_example2; json— — — -(1,3)(1 row)
复制代码


乍一看,这似乎没有什么用,但要记住:在查看生成的模式之前,请在视图、自定义类型和自定义类型的字段上定义注解,以利用 Graphile 的智能注解:


postgres_test_db=# comment on  type postgraphile.custom_type  is E’A description for the custom type’;postgres_test_db=# comment on  view postgraphile.json_object_example2  is E’A description for the view’;postgres_test_db=# comment on  column postgraphile.custom_type.”hello world”  is E’A description for hello world’;postgres_test_db=# comment on  column postgraphile.custom_type.field_2  is E’@name field_two\nA description for the second field’;
复制代码


现在,当查看模式时,json字段不再显示为不透明的类型JSON,而是显示为CustomType



(还要注意,对视图所做的注解(A description for the view)显示在查询字段的文档中)。


单击CustomType将显示自定义类型的字段及其注解:



请注意,在自定义类型中,第二个字段被命名为field_2,但 Graphile 智能注解将该字段重命名为field_two,通过 Graphile 将驼峰式大小写转换为fieldTwo。另外,对这两个字段的描述都被显示在生成的 GraphQL 模式中。

允许 Graphile 生成的模式具有“所有权限”(在开发期间)


最初,当讨论使用 Graphile 作为“一种模式来管理所有模式”架构中的一个选项时,该提议遭到了强烈的反对。关于安全性(如何将其与我们的 IAM 基础设施集成,以及如何在数据库中实施行级访问控制?)和性能(如何限制查询以避免一次选择所有行来对数据库进行 DDoS 攻击?)的合法性问题引起了人们的关注,提出了使用类似于 SQL 的查询接口以提供对数据库表的打开权限(open access)。然而,在小团队快速开发内部应用程序的 GQLMS 环境中,默认的 Graphile 行为是让所有列都可用来过滤,这允许 UI 团队可以快速迭代大量新特性,而无需后端团队的参与。这与其他开发模型不同,在其他模型中,UI 和后端团队首先就初始 API 契约达成一致,后端团队实现 API,UI 团队使用 API,然后 API 契约随着 UI 需求在开发生命周期中的变化而演变。


最初,整个应用程序的性能很差,因为 UI 通常需要多次查询才能获取所需的数据。然而,一旦应用程序的行为被充实起来,我们就可以快速创建新视图,以满足每个 UI 交互的需求,这样每次交互只需要一个调用即可。因为这些请求是以本机代码运行在数据库上,所以我们可以通过适当地使用索引、去规范化、集群等来执行复杂的查询并获得高性能。


一旦 UI 和后端之间的“公共 API”(“public API”)固化,我们就“加固”了 GraphQL 模式,通过使用智能注解@omit标记表和视图来删除所有不必要的查询(由 Graphile 的默认设置创建)。另外,Graphile 的默认行为是为表和视图生成突变,但是智能注解@omit create,update,delete将从模式中删除突变。

结论


对于那些采用模式优先方法进行 GraphQL API 开发中的用户来说,Graphile 的自动 GraphQL 模式生成功能可能会对模式设计者造成难以接受的限制。如果需要细粒度的访问控制,Graphile 可能很难集成到现有的企业 IAM 基础设施中。向 Graphile 生成的模式中添加自定义查询和突变(即公开 UI 所需的 gRPC 服务调用)是我们目前在 Docker 镜像中不支持的。然而,我们最近注意到 Graphile 的 makeExtendSchemaPlugin,它允许将自定义类型、查询和突变合并到 Graphile 生成的模式中。


也就是说,在初始需求有限并且有一个临时的分布式团队(之前没有合作过)的情况下,一个内部应用在 4-6 周内就能成功实现,这引起了整个 Netflix Studio 的极大兴趣。Netflix 的其他团队也正在寻找对应的 GQLMS 方法:


  1. 使用标准的 GraphQL 构造函数和实用程序将数据库公开为 API

  2. 利用自定义的 PostgreSQL 类型构建 GraphQL 模式

  3. 通过从数据库自动生成大型 API 来提高灵活性

  4. 并在 Graphile 生成的业务逻辑和数据类型之外,额外公开其他自定义的业务逻辑和数据类型


这是一个替代之前使用 REST 实现内部 CRUD 工具的可行解决方案。拥有托管 Graphile 的标准化 Docker 容器为团队提供了必要的基础设施,通过这些基础设施,他们可以快速迭代新工具的原型以及快速开发应用程序,从而解决全球媒体工作室在这个充满挑战时期内不断变化的需求。


原文链接:


https://netflixtechblog.com/beyond-rest-1b76f7c20ef6

2021-03-31 15:023829

评论

发布
暂无评论
发现更多内容

什么是IP冲突以及如何解决?

郑州埃文科技

IP地址 IP冲突

查找端口占用并关闭进程(windows)

liuzhen007

端口占用 5月月更

nginx配置系列(九)nginx中的防盗链

乌龟哥哥

5月月更

软件测试需要学什么?测试学习大纲梳理

伤心的辣条

Python 程序员 程序人生 软件测试 自动化测试

位运算——Java语言描述

工程师日月

位运算 java 5月月更

焱融科技在高性能全闪文件存储系统设计的思考

焱融科技

云计算 分布式 云原生 高性能 文件存储

恒源云(Gpushare)_今日炼丹小疑问:如何给数据加权重?

恒源云

Python 深度学习 PyTorch

测试人生 | 00后0经验应届毕业生拿下2线城市15W offer,好励志~

伤心的辣条

Python 程序人生 软件测试 自动化测试 接口测试

成功转行测试,分享一下自己的经验【思维导图】初级/中级/高级测试工程师会哪些...

伤心的辣条

Python 程序人生 软件测试 自动化测试 测试开发

CleanMyMac有没有需要安装电脑?

茶色酒

CleanMyMacX

MathType2022永久无限试用脚本程序

茶色酒

MathType

从开源模型、框架到自研,声网 Web 端虚拟背景算法正式发布

声网

AI 大前端 WebRTC webassembly Dev for Dev

DevOps系列之 —— 持续规划与设计(二)规划与设计

若尘

DevOps 5月月更

LabVIEW串口通信

不脱发的程序猿

LabVIEW 串口通信 数据通信

【国产免费】ETL任务调度运维自动化平台 TASKCTL 作业互斥与强制依赖

敏捷调度TASKCTL

DevOps 分布式 运维 ETL 大数据运维

得物客服一站式工作台卡顿优化之路

得物技术

前端 优化 sdk 卡顿 iframe

Flutter 如何快速切换生产和测试环境?

岛上码农

flutter 安卓开发 ios 开发 跨平台应用 5月月更

时序数据库在博物馆环境检测的应用

CnosDB

IoT 时序数据库 开源社区 CnosDB infra

Hexo+github搭建个人博客,并绑定域名

武师叔

5月月更

做SaaS的程序员们,是时候关注企业架构了

AI架构师汤师爷

企业架构 SaaS 架构设计 5月月更

技术打开感知世界:当感官数字化,会发生什么?

脑极体

MathType全新免费版数学公式编辑器

茶色酒

MathType

LabVIEW十六进制和字符类型转换

不脱发的程序猿

LabVIEW 进制转换

【愚公系列】2022年05月 二十三种设计模式(六)-适配器模式(Adapter Pattern)

愚公搬代码

5月月更

恒源云 (Gpushare)_【炼丹必备】调参心法(说人话系列)

恒源云

深度学习

linux之autojump命令

入门小站

Linux

在线URL编码加密工具

入门小站

工具

LabVIEW应用程序后台运行

不脱发的程序猿

LabVIEW

使命与愿景

Ian哥

项目管理 企业文化 使命愿景

HarmonyOS 2迎来大更新:10个功能升级,这些机型建议更新!

科技汇

六、高可用之流控降级

穿过生命散发芬芳

5月月更 高可用设计

超越 REST_架构_Dane Avilla_InfoQ精选文章