写点什么

超越 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:023533

评论

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

一文带你全面了解java对象的序列化和反序列化

华为云开发者联盟

Java 序列化 java对象 反序列化 Serializable接口

JavaScript设计模式之单例模式

程序员海军

JavaScript 大前端 设计模式 单例模式

如何下载和保存YouTube上的中英双语字幕和视频

flyfk

字幕

凭借师兄甩给我的通关秘籍,顺利拿到字节Offer

学Java关注我

Java 编程 架构 面试

GitHub开源的文言文编程语言、程序生成中国山水画、格律诗编辑程序

不脱发的程序猿

GitHub 开源 编程语言 传统文化

干好开发者关系的十个职业发展秘诀

开发者关系

开发者关系 技术运营 DevRel

Java程序员面试必备——过得了面试官,过不了HR?我教你

比伯

Java 编程 架构 程序人生 计算机

5月20日,GaussDB将有大事发生

华为云开发者联盟

数据库 云原生 华为云 GaussDB TechWave

高德 Serverless 平台建设及实践

Serverless Devs

阿里云 Serverless 云原生

云厂商下一块必争之地就是它了!

Serverless Devs

Serverless 云原生

414天前,我以为这是编程玄学...

why技术

Java JVM JMM

阿里大牛亲码 Spring AOP详解笔记全网开源,学透并发只需3天

飞飞JAva

spring aop

来了!这份阿里P7大佬梳理的Java注解和反射精髓笔记,信息量过大

飞飞JAva

Java

被解救的代码 - 代码即服务时代来了!

Serverless Devs

阿里云 Serverless 云原生

一线大厂最新总结Spring Security Oauth2.0认证授权全彩笔记

Java架构追梦

Java 阿里巴巴 架构 面试 spring security

停止维护的CentOS6,怎么使用yum?

运维研习社

Linux 5月日更

【智慧农业】从“看天吃饭”到“知天而作”,乡村振兴全靠 TA

IoT云工坊

人工智能 物联网 智慧农业 庭院灌溉 温室大棚

消息队列的两种模式

五分钟学大数据

kafka 5月日更

Apache Hue介绍

大数据技术指南

hue 5月日更

消除数据孤岛,华为云DRS让一汽红旗ERP系统数据活起来

华为云开发者联盟

数据库 GaussDB 数据孤岛 华为云DRS ERP

300条数据变更引发的血案-记某十亿级核心mongodb集群部分请求不可用故障踩坑记

杨亚洲(专注MongoDB及高性能中间件)

数据库 mongodb 架构 MySQ 分布式数据库mongodb

10个 解放双手的 IDEA 插件,这些代码都不用写(第二弹)

程序员小富

Java 后端 IDEA

青海大学智慧微能源数字孪生可视化系统

ThingJS数字孪生引擎

大前端 可视化 3D可视化 数字孪生

IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

JackJiang

即时通讯 IM 扫码

GitHub霸屏文章!清华教授手写保姆级笔记Scala - 类,网友:太香了

牛哄哄的java大师

Java scala

苹果移动设备用什么管理比较好?有什么推荐?

懒得勤快

imazing 手机管理

前端项目上传图片,压缩,拍照图片旋转解决方案

Vue js canvas axios

【技术干货】文件系统中的“锁”

焱融科技

容器 分布式 云原生 高性能 文件存储

python解释器+pycharm的安装

Geek_6370d5

#python学习之路

拥有一个高性能低延时数据库是什么样的体验?

华为云开发者联盟

数据库 华为云 GaussDB GaussDB(for Cassandra) 低延时

阿里P7:每个码农都应该知道的MySQL主从复制方法,看这篇就够了

牛哄哄的java大师

Java MySQL 数据库

超越 REST_架构_Dane Avilla_InfoQ精选文章