如何描述故意打破REST标准的架构转变?


37

我正在提议对一个架构很差的软件项目进行更改,该项目会遇到很多问题。在较高的层次上,该项目在前端使用了Angular,并使用了各种REST API。一切都很棒(我看不到需要更改我们的技术或工具)。问题在于,UI中的代码库比服务器端API大得多。大多数业务逻辑都存在于UI中,而REST API是与UI层的简单CRUD数据库接口。

例如,发给客户的POST将创建客户记录,而PUT将修改该客户。不多,也不少。但是,我们的业务逻辑要求更高。创建客户的一般过程所要做的不仅仅是插入1条数据库记录。它将在其他必要的表中提供数据,执行某些验证和计算等。我更愿意进行单个POST / PUT调用来封装所有这些行为,从而减轻使用方客户端的负担。

因此,我的观点是,这种总体编排应该驻留在服务器(我们拥有完全控制权,日志等)上,而不是UI上,但是一个反对意见是该方法将不再是RESTful。因此,当我的建议是继续使用现有的技术堆栈,但在代码所属的位置实现根本的转变时,我不确定如何最好地描述这种方法。


44
为了使其成为“ RESTful”,将API限制为CRUD调用是一个很不好的权衡。
罗伯特·哈维

38
@EsbenSkovPedersen:永远最好的朋友?
罗伯特·哈维

5
我不必担心服务是否符合REST(iirc,几乎没有),而更担心符合HTTP规范。我使用过的大多数api都不符合规范,但这是一个更容易实现且更有价值的目标imo。
aaaaaa

7
@aaaaaa,几乎没有服务符合REST的原因是没人能决定REST是什么。我发现的唯一共识是“其他人都做错了”。
马克

16
-“如何描述故意破坏REST标准的架构转变?” - 别担心。(对不起,非专业的评论,它比我更强大。
luk32

Answers:


49

当我的建议是继续使用现有技术堆栈,但在代码所属的位置进行根本性的改变时,我不确定如何最好地描述这种方法。

Service oriented architecture

您建议重新设计系统,以使业务规则和数据位于同一位置。这实际上是服务的定义;请参阅Udi Dahan在“ 寻找服务边界”上的演讲。

侧边栏:正如Eric所述,这与“ REST”无关。绝对没有理由不能将REST API(即满足REST体系结构样式约束的API )放在服务的前面。但这对于了解REST的人来说并不明显,这意味着将数据库操作映射到HTTP方法。

在改变听众对REST的理解上,也许值得或不值得投资。


32
根本不值得在REST上进行投资。如果您阅读Roy Fielding的论文(或我如何向我的妻子解释REST),则REST的真正目的是为Internet上的资源提供规范的表示形式,以便跨Internet的不同机器将具有处理这些资源的标准方法。 。 私有应用程序甚至可能不需要此功能。
罗伯特·哈维

29

REST不是CRUD。这种“反驳”是基于对REST是什么的根本上错误的理解。我在您的帖子中没有看到任何表明您所做的更改将使您的API或多或少RESTful的信息。


6
嗯,不,这不是到CRUD的完美映射,但是它确实像CRUD一样走路和说话,唱歌,至少在大多数人的解释方式上是如此。
罗伯特·哈维

11
@RobertHarvey我认为这是(误)理解的问题所在。
JimmyJames

4
@JimmyJames:这是一种普遍的误解。当大多数人甚至不了解好处是什么或这些好处将如何应用到他们身上时,就会有强烈的动力使事情变得“轻松”。
罗伯特·哈维

4
@RobertHarvey我想您是说如果以错误的方式进行REST,那么REST应该不是目标。可以,但是从我的角度来看,称其为“非REST”是胡说八道,而我是支持胡说八道的大力支持者。 单词需要一个普遍理解的含义才能有用。
JimmyJames

5
@RobertHarvey同意,但是只要有足够的人愿意纠正这些对术语的误用就不会发生。我还没准备好扔毛巾。
JimmyJames

24

需要记住的另一件事是:不验证您的业务规则服务器端,意味着您隐含地信任通过POST请求传入的任何内容都是有效的。

举例来说,这意味着,虽然您的角度应用程序可能会检查客户是否具有有效的年龄范围并确保合法用户获得正确的反馈,但是任何知道您的api网址的人都可以发出包含一些非合法值的POST请求,不再被验证。

因此,我的建议是将您的业务规则移至API,让其验证输入并在响应的正文中返回适当的错误(或者可能只是指示错误的代码)。然后,您的前端应用程序可以使用这些代码来指示出了什么问题。


5
到目前为止,这是最有用的答案:API是攻击面,而不是客户端的输入。任何API请求都可以被欺骗。因此,纯API可以完成的所有工作,都是无才,恶意的脚本小子可以做的。可以使用客户端软件来提供更好的用户体验,但是服务器需要执行规则。
cmaster

10

要在此处添加其他好的答案:

您的界面(无论是REST还是其他方式)都不应基于围绕实现细节的某种假设而受到限制。这与作为抽象层的服务的概念完全相反。

使用服务的主要好处之一是无需客户做任何事情就可以更改实现细节。根据您的描述,听起来好像没有真正的抽象层。实现的详细信息已通过HTTP公开。REST并没有说这是必要的,有用的或可取的。实际上,我认为我可以说服REST定义的某些部分来表示这实际上是一个非RESTful实现。

您的建议是如何设计适当的服务层。如果有人告诉您您不能做到这一点,因为它不是RESTful的,那是不幸的。您可以放心,告诉您的人对REST几乎一无所知。

根据您的问题,您有一个称为客户的资源。可以并且应该将创建有效客户资源的一切所需的一切都处理POST到客户基础资源中(或者,如果不存在,则在PUT中替代/可选地在特定客户资源中进行处理)。REST没有说明有多少资源您需要在给定调用上创建的数据库记录。正如Colin Young评论的那样,根本不需要数据库,从REST角度实现服务完全无关紧要。


3
REST没有说数据库记录,更不用说有多少记录了。我可以创建一个REST服务来控制水阀,并公开水阀,供水和水箱水位资源。您可能会说物理对象本身就是一个“数据库”,但是有点牵强。
科林·杨

@ColinYoung是的,谢谢您的澄清。
JimmyJames

3

这里有一些很好的答案,但是我不确定它们是否可以帮助您说服您的同事。正如许多人指出的那样,您的建议并不意味着放弃RESTful设计,而我认为这是使它们符合您的建议的关键。

REST 并不是要确保您的API仅允许存储和检索数据。相反,它与将动作建模资源有关。您的API 应该允许采取措施(毕竟,它是一个应用程序编程接口)。问题是如何为这些行为建模。

举个例子,而不是提出一个术语,可能是向您的同事解释这个问题的最好方法。通过这种方式,您可以显示他们现在正在做的事情,这将导致什么问题,解决该问题的解决方案以及如何仍然保持RESTful。

让我们看一下您的Customer对象。

问题:

UI将POST客户,但后续表尚未更新。如果后续调用之一由于您的UI代码错误(或浏览器插件的行为异常)而失败,该怎么办?现在,您的数据处于不一致状态。它甚至可能会破坏您的API或UI的其他部分,更不用说它只是无效了。您如何恢复?您必须测试每种可能的状态,以确保这不会破坏某些内容,但是要知道什么是可能的却很难。

解:

创建一个API端点以创建客户。您知道您不想拥有“ / customer / create”甚至“ / create-customer”端点,因为create是一个动词,会违反REST。因此将其名词化。“ / customer-creation”可能有效。现在,当您发布CustomerCreation对象时,它将发送所有需要的字段以完全创建客户。端点将确保数据完整且有效(例如,如果验证失败,则返回400或类似值),并且可以将所有数据持久保存在单个db事务中。

如果您还需要一个端点来获取/ customer对象,那很好。您可以同时拥有。诀窍是创建可满足消费者需求的端点。

好处:

  1. 您保证您不会陷入不良状态
  2. 实际上,如果UI开发人员不必“知道”请求的顺序,验证问题等,则实际上更容易
  3. 它不像API那样健谈,减少了网络请求的延迟
  4. 更容易测试和概念化方案(UI中丢失/格式错误的数据不会分散在请求中,其中一些可能会失败)
  5. 它可以更好地封装业务逻辑
  6. 通常使安全性更容易(因为用户可以修改UI中的业务和业务流程逻辑)
  7. 可能会减少逻辑重复(与2个以上可以访问相同数据的API相比,您有2个以上的API使用者)
  8. 仍然100%RESTful

缺点:

  1. 对于后端开发人员来说,这可能需要做更多的工作(但从长远来看可能不会)

人们可能很难理解这种范例,如果他们没有尝试过,对它有什么好处。希望您可以通过使用自己代码中的示例来帮助他们了解。

我自己的经验是,一旦我团队中的开发人员开始实施该策略,他们几乎会立即看到好处。

进一步研究:

Thoughtworks的这篇文章确实帮助我有了使用实际示例将动作建模为对象的想法:https : //www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling

我还建议您阅读CQRS和事件源,因为它们恰恰与此类事情有关(即,使API与实际的持久性逻辑脱节)。我不知道您的同事会多么愿意阅读此类内容,但这可能会使您更加清楚并帮助您向他们解释。


因为create是一个动词,会违反REST ” –绝对正确。换句话说,这将是在47.258.346中运行“基于REST的RPC ”的方法。至少我会将此归因于“非自然的”,因为它滥用和错误地代表了RESTful方法(它们确实有其用例,但RPC不是其中一种),而且往往效率很低。
JensG '18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.