使用API​​创建多种资源(不同类型)的干净方法 [英] Clean way to create multiple resources (different types) with an API

查看:130
本文介绍了使用API​​创建多种资源(不同类型)的干净方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于API的开发,我们希望使用干净的RESTful API设计通过一个表单提交(注册)为该组织创建一个新组织和一个新用户.

For the development of an API we want to create a new organization and a new user for that organization with one form submission (the registration) using a clean RESTful API design.

由于我们不想混用不同的资源(组织和用户)并通过一个呼叫来创建资源(该呼叫的响应是组织还是用户?),我们需要将注册分为两个呼叫:首先创建组织,然后在创建用户之后立即创建组织.

As we don't want to mix different resources (organizations and users) and create the them with one call (the response of that call is it an organization or an user?) we need to split the registration into two calls: create organization first and directly after create user.

但是,如果将用户和组织的创建分为两个独立的API调用,则会看到以下问题:

But if the user and organization creation is split into two independent API calls we see the following problems:

  1. 如何处理错误?例如.如果创建组织成功,但是创建用户由于错误而失败(例如,用户电子邮件已经存在).在这种情况下,将创建一个没有任何用户的组织,没有人可以登录以更改组织资源.
  2. 创建组织后如何处理授权?具有组织ID的每个人都可以简单地创建一个新用户而无需任何登录检查(只能使用电子邮件和密码登录)吗?还是创建组织会返回令牌以创建第一个用户? (令牌逻辑将使客户端变得相当复杂:如何处理重新提交等)

推荐答案

如何处理错误?例如.如果创建组织成功,但是创建用户由于错误而失败(例如,用户电子邮件已经存在).在这种情况下,将创建一个没有任何用户的组织,没有人可以登录以更改组织资源

How to handle errors? Eg. if the create organization is successful but the create user fails due to an error (eg. user email already exists). In that case an organization without any user is created and nobody can login to change the organization resource

除了 PATCH 之外,没有一种标准的HTTP方法能够真正解决事务性问题.行为. PATCH,即要求补丁文档中定义的所有指令步骤都必须进行原子处理.要么全部应用要么都不应用.因此,如果一条指令失败,则无需进行任何修改.但是,PATCH和其他方法之间的区别在于,PATCH应该包含一组指令以应用于一个或多个资源,而另一种操作通常在某种意义上针对单个文档.

Except for PATCH none of the standard HTTP methods really tackles a transactional behavior. PATCH i.e. demands that all of the instruction steps defined within the patch document need to be processed atomically. Either all or none of them have to be applied. So if one instruction fails none of the modifications must be applied. The difference between PATCH and the other methods however is, that PATCH should contain a set of instructions to apply onto one or multiple resources while the other operation in a sense target a single document usually.

如果从文档管理系统查看,HTTP确实是其核心,因为您得出的任何业务规则都只是文档管理的副作用(请参见规范在此处提到,PUT允许有以下内容-效果. IE.与GIT类似,在GIT中,尽管仍然可以通过其自己的URI访问实际的提交,但提交将推动进程前进. DELETE删除URI与存储的文档的关联.这是否导致在假想文件系统上删除文档是一个实现细节. GET只会将该文档的内容返回给调用者,并 POST 仅根据服务自己的语义处理请求,而不会进一步承诺如何处理有效负载.因此,是否创建一个或多个资源,或者甚至根本不创建,取决于实现方式.但是,如果创建资源,则需要返回包含Location标头的201 Created响应,该标头带有新创建资源的URI,以向客户端提示有关新创建资源的信息.在创建多个资源的情况下,规范不太清楚在那种情况下应该返回什么,因为只有一个Location标头可能会出现在响应中.

If viewed from a document management system, which HTTP truely is at its heart as any business rules you conclude are just a side-effect of the document management (see this great talk), the operations of HTTP make a bit more sense. I.e. PUT replaces the current document with the one provided. If none existed so far it is similar to a document creation. The spec here mentions that PUT is allowed to have side-effects. I.e. similar to GIT where a commit will push the head forward though the actual commit will still be accessible via its own URI. DELETE removes the association of the URI to the document stored. Whether that leads to a document removal on the imaginary filesystem or not is an implementation detail. GET will only return the content of that document to the invoker and POST only processes the request according to the service own semantics giving no further promises on what it does with the payload. So whether one or multiple resources are created, or even none at all, is up to the implementation. However, if you create resources you need to return a 201 Created response containing a Location header with the URI of the newly created resource that hints clients about the newly created resource. In the case of multiple resources being created, the spec is a bit less clear what should be returned in that case as only one Location header may appear within the respone.

基于表单的创建方法的使用肯定是一种RESTful方法,因为服务器在这里教导客户端有关执行任务所需的输入.客户端通常对服务器实际如何处理和存储数据的兴趣不大,它所感兴趣的只是成功完成请求或暗示服务器在处理请求时遇到的问题.

The usage of a form-based creation approach is for sure a RESTful approach as here the server teaches a client on the needed inputs to perform the task. A client usually isn't that much interested in how the server is actually processing and storing the data, all it is interested in is the completion of its request, either successfully or with a hint on the problems the server had while processing the request.

您是必须一次性选择创建所有内容还是将每个部分划分为自己的请求. IE.在一个典型的网站上,您可能会遇到类似怪癖"的方法,即您首先在表单中输入一些与组织相关的信息,单击提交"按钮,然后获得进一步的表单响应,要求您输入用户详细信息以及进一步的响应,以汇总详细信息并询问确认.数据可以存储在一些临时资源中,该临时资源在确认摘要后将一次性创建所有内容,从而模仿了某些原子处理,从而在用户详细信息等遇到一些问题的情况下使组织的创建失败了.如果您有多个取决于先前选择的可选数据,则这种方法很方便.

Whether you create everything in one go or divide each part to its own request is some choice you have to make. I.e. on a typical Web site you may encounter a wizzard like approach were you enter some organization related information first into a form, click a submit button and then get a further form response asking you to enter user details with a further response summarizing the details and asking for confirmation. The data could be stored in some temporary resource that on confirming the summary will create everything in one go mimicking some kind of atomic processing failing the creation of the organization in case some problems were encountered with the user details and such. Such an approach is convenient if you have multiple optional data that depends on previous choices.

当然,您也可以以一种单一形式输入数据,然后通过POST请求将其发送到服务器,然后以这种方式创建相应的资源.在Location标头中返回哪个URL仍然是一个不同的决定.如果要创建的主要资源是我要选择组织URI的组织,特别是如果它允许列出其定义的用户.在内部,您可以利用事务来确保组织和用户之间的状态一致,而如果做不到这一点,则只需回滚事务并将错误返回给用户即可.

Of course you could also enter the data in one single form and send it to the server via a POST request and then create the respective resources that way. Which URL to return in the Location header is yet a different decision. If the main resource being created is the organization that I'd opt for the organization URI, especially if it allows to list its defined users. Internally you can utilize transactions to guarantee a consistent state between organization and user and in a failure to do this you simply can roll back the transaction and return an error to the user.

如果您尝试将创建分为多个步骤,那么您肯定必须处理用户资源及其对组织资源的影响的例外情况.如前所述,HTTP没有提供任何有关HTTP的提示,这是两个独立且不相关的请求.在这里,不是服务器应该是聪明的事情,而是客户端必须是聪明的事情.如果在创建用户时遇到问题,则应执行组织本身的清理.在这种情况下,服务器/API只是被视为愚蠢的存储对象.

If you attempt to divide the creation into multiple steps you surely will have to deal with the exception case of the user resources and its effects on the organization resource. As mentioned HTTP does not give any hints on that as to HTTP these are two separate and unrelated requests. Here, not the server should be the smart thing but the client has to be. If it encounters problems while user creation it should perform the cleanup of the organization itself. The server/API is just seen as dumb storage thing in such a case.

创建组织后如何处理授权?具有组织ID的每个人都可以简单地创建一个新用户而无需任何登录检查(只能使用电子邮件和密码登录)吗?还是创建组织会返回令牌以创建第一个用户? (令牌逻辑将使客户端变得相当复杂:如何处理重新提交等)

How to handle the authorization after creating the organization? Can everybody with the organization id simply create a new user without any login check (login is only possible with email and password)? Or will the create organization return a token to create the first user? (The token logic will make the client quite complicated: how to handle resubmissions etc.)

这基本上取决于您的设计.通常,应将某种权限管理添加到API.某些框架已经包含了对此的支持,即在Java和Spring生态系统中,您可以在操作端点和业务方法上添加某些批注,以检查某些已分配的用户角色和权限,并且仅在可用时才允许访问.

It basically depends on your design here. Usually some kind of permission management should be added to the API. Some frameworks already contain support for such, i.e. in the Java and Spring ecosystem you can add certain annotations onto operation endpoints and business methods that check certain assigned user roles and permissions and only allow access if they are available.

如果您将组织和用户创建方法分开,并且在用户创建期间遇到问题,则可以将表单发送回客户端,以请求其他用户详细信息,因为其他组织已经存在该用户的详细信息,直到返回有效数据为止.现在,大量基于Web的API通过邮件发送一些确认链接以验证电子邮件地址的正确性,并且用户只有在第一次单击该电子邮件中的激活链接时才登录".在纯HTTP中,您将发送包含用户凭据的HTTP Authorization标头.在没有激活用户的情况下,该服务将返回401 Unauthorized作为失败,从而阻止用户向该服务进行身份验证.在这种情况下,外部管理实体(即API的项目经理或管理员)必须为该组织创建一个用户,并将数据发送给请求者.但是,应高度避免IMO使用这种状态.我想,在这里,探查用户是否可以接受的用户详细信息肯定是可取的.

In case you have a split organization and user creation approach and encountered a problem during user creation you could send a form back to the client requesting other user details as one already exist for an other organization until valid data was returned. Plenty of Web-based APIs nowadys send some confirmation links via mail to verify the correctness of the email-address and the user is only "logged-in" the first time when he clicked the activation link in that email. In pure HTTP you'd send a HTTP Authorization header containing the user credentials. In the absence of an activated user the service would return 401 Unauthorized as failure preventing the user from authenticating with the service. In such a case an external administrative entity (i.e. a project manager or administrator of the API) would have to create a user for that organization and send the data to the requestor. Though, such a state should be highly avoided IMO. Here, probing a user for admissible user details is sure preferrable, I guess.

对于未分配用户以释放资源并避免携带不稳定状态的组织,在给定阈值量之后,您还可能在后台运行某种清理例程(或执行手动清理任务).您的定义,因为必须将用户分配给组织.

You might also run some kind of cleanup routine in the back (or perform a manual cleanup task) after a given threshold amount on organizations that have no user assigned to it to free up resources and avoid carrying arround inconsitent state, according to your definition, as there has to be a user assigned to an organization.

如您所见,如何处理这种情况有两个设计选择.您是以一种形式输入数据并一次将所有内容发送到服务器,还是使用临时资源从n个连续的表单请求中收集数据,直到用户确认数据并以原子方式一次处理所有内容,或者使用专用的请求任务,并有一些支持例程来检查系统的一致性由您决定.

As you see, you have a couple of design choices how to tackle such a scenario. Whether you enter the data in one form and send everything in one go to the server or use a temporary resource to collect data from n consecutive form requests until the user confirms that data and you process everything in one go atomically or you use dedicated requests per task and have some backing routines that check the consitency of the system is up to you.

关于标题中提及的内容的最终注释. REST客户端不应将资源视为特定类型,因为这会导致客户端期望某些终结点返回某些

A final note on a thing mentioned in your title. REST clients shouldn't consider resources to have a specific type as this leads to clients expecting certain endpoints to return certain types. This also leads to clients interpreting URIs to determine the type of that resource. As the server is free to change its URI scheme any time it wants to, chances are that clients wont be able to determine the type based on the URI automatically without a developer building in that kind of knowledge into the client. This avoids the actual benefits a REST architecture should provide, namely the freedom for evolution in future that is enabled by the decoupling of clients from servers. Instead of using typed resources clients should rely on content-type negotiation where standardized representation formats understood and supported by both, client and server, are exchanged. The media-types defining these representation formats specify the processing rules and semantics of each of the elements within the payload and allow interoperability.

这篇关于使用API​​创建多种资源(不同类型)的干净方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆