随着架构的解耦和微服务架构的兴起,每个开发者都不可避免地会使用REST来构建API并与REST进行交互。然而,我们真的了解并充分利用当代REST和超媒体的优势吗?本文将与您一起研究2020年的REST和超媒体。概述REST被认为是一堆抽象层,有助于减少与客户端开发人员的交互,同时能够构建更健壮和一致的应用程序。这可以通过多种方式实现,主要是依靠RESTAPI所在协议的现有语义,通常是HTTP。在HTTP中构建RESTAPI是关于遵循现有的HTTP语义来实现REST建议实现的概念,而不是发明您自己的约定。客户无需编写一堆代码来了解API可能响应的每个应用程序错误,客户可以查询Retry-After标头并自行处理错误代码。开发人员抱怨REST很难,因为必须理解HTTP方法及其含义以及不同的状态代码。虽然学习HTTP可能需要一些时间,但HTTP的约定与广泛的工具生态系统共享。开发者一致反对这些技术,很多时候他们更喜欢RPC。对于很多开发者来说,在网上运行这些API就足够了,他们可以自己在上面添加操作和约定,这样他们也可以获得一些需要的功能CRUD(POST,GET,PUT,DELETE=Create,Read,Update,删除)增删改查,失去了很多REST架构所能提供的好处。“REST是RPC之上的一堆抽象层”?Richardson的成熟度模型结构图如下:这是MartinFowler的文章介绍《Richardson成熟度模型》的总结图。该模型以LeonardRichardson的名字命名,讨论了API成熟度。该图有一些常见的问题,主要是顶部的“GloryofREST”和底部的混乱。不幸的是,这让RESTAPI看起来像一个迷宫,其他一切都一团糟。REST的好处是显而易见的:网络上的所有东西都可以抽象为资源(Unify);每个资源都有一个统一且唯一的资源标识符(URI);使用标准方法操作资源;所有操作都是无状态的;可以缓存以提高性能。另一个问题是Martin正在谈论PlainOldXML,最近有人在谈论POJO(PlainoldJSONObjects)。API规范(用于描述数据模型的元数据)适用于所有API开发人员,无论他们的范例或选择的实现如何,因此应予以考虑。REST的人使用JSONSchema,gRPC的人使用Protobuf,而GraphQL的人有GraphQL类型。Richardson成熟度模型的改进我们改进了上面提到的Richardson成熟度模型,每一层都简要提到了它启用的一些功能。RPC的真正问题在于,在其最基本的形式中,RPC经常忽略许多HTTP概念。它不会使用HTTP的统一接口及其完整语义,也不会使用HTTP作为传输协议,而只会使用传输方面的内容。传输协议可以帮助您了解何时或是否需要发出请求,而不仅仅是通过网络发送数据。大多数RPC实现与单个端点交互,并且大多数交互使用单个HTTP方法。很少有常见的HTTP约定只能用于最基本的RPC。如果RPC遵循特定标准,则可以使用为该标准构建的工具,但一般的HTTP约定不适用。资源这里有两个常见的混淆,首先这不是关于/bikes、/bikes/abc123而是经常使用的标准集合、复数和资源CRUD模式。从技术上讲,资源与端点是一回事,但有一个有意的区别。端点通常被认为更像函数,其目的是在想要做某事时调用函数,但这也是大多数传输的传输方式,并且通常是RPC思想的标志:调用某事并做某事.资源更像是一个标识符,它是在特定位置可以被那个东西识别的唯一的东西。它是HTTP世界中的最终唯一标识符,尽管可能有不同的产品具有相同的字母/数字ID,并且UUID也有可能发生冲突。URI(统一资源标识符)对所有内容都是唯一的。通过这种方式,我们可以将特定的标头添加到不同的资源中,这些资源可以作为元数据与响应一起存储。通过这种方式,资源可以声明它们自己的可缓存性,这是REST谈论的重要内容之一。缓存约束要求响应请求的数据被隐式或显式标记为可缓存或不可缓存。如果响应是可缓存的,则授予客户端缓存权限,以便为以后的等效请求重用响应数据。添加缓存约束的好处是可以部分或完全消除某些交互,从而通过降低一系列交互的平均延迟来提高效率,提高系统的可扩展性和用户感知性能。HTTP/1.1中缓存的目标是通过重用以前的响应消息来满足当前请求来显着提高性能。如果响应可以在没有“验证”的情况下重复使用,则存储的响应被认为是“新鲜的”(检查原始服务器以查看缓存的响应是否对该请求仍然有效)。因此,每次重复使用响应时,新响应都会减少延迟和网络开销。当缓存的响应不是“新鲜的”时,如果可以通过验证刷新它或者原始响应不可用,则可以重用它。如果它有唯一的URI,它也可以在HTTP/2中轻松升级。HTTP方法方法为请求中发生的事情的类型添加了很多重要的语义。如果使用缓存,缓存组件将知道它可以缓存GET请求,但如果对同一资源执行POST或DELETE操作,它就会知道它应该避免它。现在可以实现像自动重试这样的客户端逻辑。当API需要很长时间才能响应时,重试会有所帮助,并且客户端应用程序可能会放弃请求并重试。使用GET有一些缺点,它是一个幂等请求,不应该有任何破坏性的行为。重试POST可能很危险,因为它可能会在超时之前更改数据库中的某些记录、发送一些电子邮件、从信用卡中扣款等。PUT和PATCH就可以了,PUT也是幂等的,只是把结果消去,而PATCH通常有一个“from”和一个“to”,也就是说如果第二次请求,from可能不匹配.作为RPC的忠实粉丝,!gRPC“HTTPBridge”添加了两个抽象层以使其更像HTTP。超媒体控件超媒体控件是“超媒体作为应用程序状态引擎”(HATEOAS)的缩写,是一个非常简单的概念。API不仅仅是HTTP上的数据存储,而是成为HTTP上的状态机。它仍然有数据,但它也可以以自我描述的方式提供“下一个可用的动作”。考虑一张说明它是应付的发票,而不是需要根据缺少paid_date来确定它是否可以支付,或者可能具有状态:待定,但也许添加新状态并等待处理并不意味着它可以支付.客户应用程序中断或需要版本控制,这两者都会浪费开发人员的时间和公司的资金。如果发票是应付帐款,会显示一个名为“付款”的链接,这意味着客户端应用程序知道什么时候付款,只要使用良好的超媒体格式,客户端应用程序就会知道如何付款,因为控制可以在向服务器发送HTTP请求之前向客户端验证数据,前提是必须提供哪些数据。超媒体的最基本级别是将链接推送到响应主体中,但客户端必须进行大量验证才能弄清楚下一步该做什么。以前,它只是:“你有一个URL和一个链接关系,这是一个很好的起点”,但现在,有很多流行的超媒体格式使这变得容易得多。REST大多数自称为REST的API没有最后一层,这意味着它们仅使用RESTish,或仅使用HTTPAPI。这很重要,因为没有超媒体控件就无法调用RESTAPI。也许开发人员根本不知道HATEOAS(超媒体作为应用程序状态引擎或超媒体约束)是什么。其他人知道,但认为HATEOAS就是强制HTTP请求加载以获取相同数量的数据。这时,他们考虑的是传输而不是转移。对于时下即将流行的HTTP/2,即使需要“更多的调用”,对性能的影响也可以忽略不计。即使在REST级别,也不意味着API在所有方面都始终可靠和完美。糟糕的资源设计会使任何API难以使用,无论您使用哪种范例。GraphQL开发人员现在开始注意到这一点。重要的是要关注满足客户需求的模型设计,API随着时间的推移而发展,修剪掉无用的数据,并创建复合资源以最大程度地减少不必要的网络延迟。JSONSchema还弃用了一个可以简化API开发的关键字。超媒体和gRPC或GraphQL在谈论超媒体控件时,通常会说“这不仅是REST可以做的事情,如果你使用HTTPBridge并添加链接,gRPC也可以做到!”一段时间以来,一位著名的GraphQL开发人员一直在尝试寻找一种将超媒体控件引入GraphQL的方法。如果他们能解决这个问题,GraphQL就不会完全遵循这个图,但我们可以调用查询和变异,它们共享语义,无论是否足够接近HTTP方法,唯一缺少的是即将到来的资源(URI)。对于GraphQL来说,缺少URI是一个更大的问题,这几乎破坏了他们直接使用HTTP/2服务器推送的机会,他们不需要转向特定于供应商的解决方案,比如ApolloSubscriptions和其他非标准的@defer类型。总结在任何情况下,API并不总是需要超媒体控件。例如,全栈开发人员通常将REST视为浪费时间,因为他们只想查询数据库并将信息传递给表示层。他们不需要将缓存控件附加到消息本身,他们只需要在客户端应用程序中设置缓存,这可能在他们计算机上的另一个窗口中打开。他们知道何时使用重试,因为他们编写了应用程序代码并且知道它们的含义,所以他们不关心是否使用了HTTP语义。这些开发人员与试图向可能位于不同楼层或大洲的各种客户团队提供一致功能的开发人员没有任何共同之处,在这些团队中,交流更改或如何推断状态可能是一个代价高昂的问题。这些团队可能正在使用各种网络和客户端工具,例如缓存中间件、服务监控、代理检查,并且不能限制他们可以使用的工具,因为这可能会使他们付出业务成本。两者之间还有其他所有完全有效的场景。不是所有的车都需要防弹玻璃,不是所有的谈话都需要麦克风,也不是所有的内衣都需要吊带。同样,并非所有API都需要是REST。
