如何创建没有动词的 REST URL?

发布于 2024-08-08 08:38:28 字数 562 浏览 2 评论 0 原文

我正在努力确定如何设计宁静的 URL。我完全赞成使用带有名词而不是动词的 URL 的宁静方法,但我不明白如何做到这一点。

我们正在创建一项服务来实施金融计算器。该计算器需要一系列参数,我们将通过 CSV 文件上传这些参数。用例将涉及:

  1. 上传新参数
  2. 获取最新参数
  3. 获取给定业务日期的参数
  4. 使一组参数处于活动状态
  5. 验证一组参数

我收集的宁静方法是具有以下类型的 URL:

/parameters
/parameters/12-23-2009

您可以实现第一个三个用例:

  1. POST 在 post 请求中包含参数文件
  2. GET 第一个 URL
  3. GET 第二个 URL

但如何在没有动词的情况下执行第四个和第五个用例呢?您不需要这样的网址吗

/parameters/ID/activate
/parameters/ID/validate

??

I'm struggling to determine how to design restful URLs. I'm all for the restful approach of using URLs with nouns and not verbs don't understand how to do this.

We are creating a service to implement a financial calculator. The calculator takes a bunch of parameters that we will upload via a CSV file. The use cases would involve:

  1. Upload new parameters
  2. Get the latest parameters
  3. Get parameters for a given business date
  4. Make a set of parameters active
  5. Validate a set of parameters

I gather the restful approach would be to have the following type URLs:

/parameters
/parameters/12-23-2009

You could achieve the first three use cases with:

  1. POST where you include the parameter file in the post request
  2. GET of first URL
  3. GET of second URL

But how do you do the 4th and 5th use case without a verb? Wouldn't you need URLs like:

/parameters/ID/activate
/parameters/ID/validate

??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

酒中人 2024-08-15 08:38:28

良好 URI 设计的一般原则:

  • 不要使用查询参数来改变状态
  • 不要如果可以的话使用大小写混合的路径;最好使用小写
  • 不要在 URI 中使用特定于实现的扩展名(.php、.py、.pl 等)
  • 不要陷入RPC 与您的 URI
  • 尽可能限制您的 URI 空间
  • 做< /strong> 保持路径段简短
  • Do 更喜欢 /resource/resource/;从您不使用的重定向创建 301 重定向
  • 不要使用查询参数来子选择资源;即分页,搜索查询
  • Do将内容从应该位于 HTTP 标头或正文中的 URI 中移出

(注意:我没有说“RESTful URI 设计”;URI 在 REST 中本质上是不透明的。)

HTTP 方法选择的一般原则:

  • 不要使用 GET 来改变状态;这是让 Googlebot 毁掉您一天的好方法
  • 不要使用 PUT,除非您要更新整个资源
  • 不要使用 PUT,除非您也可以合法地执行以下操作在同一 URI 上进行 GET
  • 不要使用 POST 来检索长期存在的信息或可能合理缓存的信息
  • 不要执行不幂等 与 PUT
  • Do 尽可能使用 GET
  • Do< /strong> 如有疑问,请优先使用 POST,而不是 PUT
  • 每当您必须执行类似 RPC 的操作时,请使用
  • POST 对于较大的资源类使用 PUT或者分层
  • Do优先使用DELETE而不是POST来删除资源
  • Do使用GET进行计算之类的事情,除非您的输入很大,在这种情况下使用POST

Web服务的一般原则使用 HTTP 进行设计:

  • 不要将元数据放入应位于标头中的响应正文中
  • 不要将元数据放入单独的资源中,除非包含它会产生重大影响开销
  • 一定使用适当的状态代码
  • 创建资源后 201 Created;资源必须在发送响应时存在
  • 202 Accepted 成功执行操作或异步创建资源后
  • 400 Bad Request 当某人执行以下操作时对明显伪造的数据进行操作;对于您的应用程序,这可能是一个验证错误;通常为未捕获的异常 401 Unauthorized 保留 500,
  • 当有人在没有提供必要的 Authorization 标头的情况下访问您的 API 或当 Authorization 中的凭据无效时;如果您不希望通过 Authorization 标头获得凭据,请不要使用此响应代码。
  • 403 Forbidden 当有人以可能恶意的方式访问您的 API 或未经授权时
  • 405 Method Not allowed 当有人在应该使用 PUT 时使用 POST,等
  • 413 请求实体太大 当有人试图向您发送一个不可接受的大文件时
  • 418 我是一个茶壶 尝试用茶壶冲泡咖啡时
  • 尽可能使用缓存标头
  • ETag<当您可以轻松地将资源减少为哈希值时, /code> 标头很好
  • Last-Modified 应该向您表明,保留资源更新时的时间戳是一个好主意
  • Cache- ControlExpires 应该被赋予合理的值
  • 一切努力来尊重请求中的缓存标头 (If-None-Modified , If-Modified-Since)
  • Do 在有意义时使用重定向,但对于网络服务来说这些应该很少见

关于您的具体问题,POST 应该用于#4 和#5。这些操作属于上面的“类似 RPC”准则。对于#5,请记住 POST 不一定必须使用 Content-Type: application/x-www-form-urlencoded。这也可以很容易地成为 JSON 或 CSV 有效负载。

General principles for good URI design:

  • Don't use query parameters to alter state
  • Don't use mixed-case paths if you can help it; lowercase is best
  • Don't use implementation-specific extensions in your URIs (.php, .py, .pl, etc.)
  • Don't fall into RPC with your URIs
  • Do limit your URI space as much as possible
  • Do keep path segments short
  • Do prefer either /resource or /resource/; create 301 redirects from the one you don't use
  • Do use query parameters for sub-selection of a resource; i.e. pagination, search queries
  • Do move stuff out of the URI that should be in an HTTP header or a body

(Note: I did not say "RESTful URI design"; URIs are essentially opaque in REST.)

General principles for HTTP method choice:

  • Don't ever use GET to alter state; this is a great way to have the Googlebot ruin your day
  • Don't use PUT unless you are updating an entire resource
  • Don't use PUT unless you can also legitimately do a GET on the same URI
  • Don't use POST to retrieve information that is long-lived or that might be reasonable to cache
  • Don't perform an operation that is not idempotent with PUT
  • Do use GET for as much as possible
  • Do use POST in preference to PUT when in doubt
  • Do use POST whenever you have to do something that feels RPC-like
  • Do use PUT for classes of resources that are larger or hierarchical
  • Do use DELETE in preference to POST to remove resources
  • Do use GET for things like calculations, unless your input is large, in which case use POST

General principles of web service design with HTTP:

  • Don't put metadata in the body of a response that should be in a header
  • Don't put metadata in a separate resource unless including it would create significant overhead
  • Do use the appropriate status code
  • 201 Created after creating a resource; resource must exist at the time the response is sent
  • 202 Accepted after performing an operation successfully or creating a resource asynchronously
  • 400 Bad Request when someone does an operation on data that's clearly bogus; for your application this could be a validation error; generally reserve 500 for uncaught exceptions
  • 401 Unauthorized when someone accesses your API either without supplying a necessary Authorization header or when the credentials within the Authorization are invalid; don't use this response code if you aren't expecting credentials via an Authorization header.
  • 403 Forbidden when someone accesses your API in a way that might be malicious or if they aren't authorized
  • 405 Method Not Allowed when someone uses POST when they should have used PUT, etc
  • 413 Request Entity Too Large when someone attempts to send you an unacceptably large file
  • 418 I'm a teapot when attempting to brew coffee with a teapot
  • Do use caching headers whenever you can
  • ETag headers are good when you can easily reduce a resource to a hash value
  • Last-Modified should indicate to you that keeping around a timestamp of when resources are updated is a good idea
  • Cache-Control and Expires should be given sensible values
  • Do everything you can to honor caching headers in a request (If-None-Modified, If-Modified-Since)
  • Do use redirects when they make sense, but these should be rare for a web service

With regard to your specific question, POST should be used for #4 and #5. These operations fall under the "RPC-like" guideline above. For #5, remember that POST does not necessarily have to use Content-Type: application/x-www-form-urlencoded. This could just as easily be a JSON or CSV payload.

思慕 2024-08-15 08:38:28

也许是这样的:

PUT /parameters/activation HTTP/1.1
Content-Type: application/json; encoding=UTF-8
Content-Length: 18

{ "active": true }

Perhaps something like:

PUT /parameters/activation HTTP/1.1
Content-Type: application/json; encoding=UTF-8
Content-Length: 18

{ "active": true }
漆黑的白昼 2024-08-15 08:38:28

每当您看起来需要一个新动词时,请考虑将该动词改为名词。例如,将“activate”变为“activation”,将“validate”变为“validation”。

但仅从您所写的内容来看,我会说您的应用程序存在更大的问题。

每当提出一个称为“参数”的资源时,每个项目团队成员都应该在脑海中发出危险信号。 “参数”实际上可以应用于任何资源;不够具体。

“参数”到底代表什么?可能有很多不同的事情,每个事情都应该有一个专门用于它的单独的资源。

另一种方式来解决这个问题 - 当您与最终用户(那些可能对编程知之甚少的人)讨论您的应用程序时,他们自己反复使用的词语是什么?

这些是您应该围绕这些词来设计您的应用程序。

如果您尚未与潜在用户进行这种转换,请立即停止一切操作,直到完成为止,不要编写另一行代码!只有这样,您的团队才会了解需要构建什么。

我对财务软件一无所知,但如果我不得不猜测,我会说某些资源可能会使用“报告”、“付款”、“转账”和“货币”等名称。

关于软件设计过程的这一部分,有很多好书。我可以推荐的两个是 领域驱动设计分析模式

Whenever it looks like you need a new verb, think about turning that verb into a noun instead. For example, turn 'activate' into 'activation', and 'validate' into 'validation'.

But just from what you've written I'd say your application has much bigger problems.

Any time a resource called 'parameter' is proposed, it should send up red flags in every project team member's mind. 'parameter' can literally apply to any resource; it's not specific enough.

What exactly does a 'parameter' represent? Probably a number of different things, each of which should have a separate resource dedicated to it.

Another way to get at this - when you discuss your application with end users (those who presumably know little about programming) what are the words they themselves use repeatedly?

Those are the words you should be designing your application around.

If you haven't yet had this conversion with prospective users - stop everything right now and don't write another line of code until you do! Only then will your team have an idea of what needs to be built.

I know nothing about financial software, but if I had to guess, I'd say some of the resources might go by names such as "Report", "Payment", "Transfer", and "Currency".

There are a number of good books on this part of the software design process. Two I can recommend are Domain Driven Design and Analysis Patterns.

表情可笑 2024-08-15 08:38:28

URL 的设计与应用程序是否是 RESTful 无关。因此,“RESTful URL”这个短语是无稽之谈。

我认为您应该更多地阅读 REST 的实际含义。 REST 将 URL 视为不透明,因此不知道其中包含什么,是否有动词、名词或其他什么。您可能仍想设计 URL,但那是关于 UI,而不是 REST。

也就是说,让我们回答你的问题:最后两种情况不是 RESTful 的,也不适合任何类型的 Restful 方案。这些就是您可能所说的 RPC。如果您认真对待 REST,则必须从头开始重新思考应用程序的工作方式。要么放弃 REST,只将您的应用程序作为 RPC 应用程序。

嗯,也许不是。

这里的想法是,您必须将所有内容视为资源,因此一旦一组参数有了一个 URL,您就可以从中引用它,您只需添加:

GET [parametersurl]/validationresults

POST [paramatersurl]
body: {command:"activate"}

但同样,激活的东西是 RPC,而不是 REST。

The design of your URLs has nothing to do with whether your application is RESTful or not. The phrase "RESTful URLs" is therefore nonsense.

I think you should do some more reading on what REST actually is. REST treats the URLS as opaque, and as such doesn't know what's in them, whether there are verbs or nouns or whatever. You might still want to design your URLs, but that's about UI, not REST.

That said, let's get to your question: The last two cases are not RESTful and don't fit into any kind of restful scheme. Those are what you might call RPC. If you're serious about REST, you'll have to rethink how your application works from the ground up. Either that or abandon REST and just do your app as an RPC app.

Hrmmm maybe not.

The idea here is that you have to treat everything as a resource, so once a set of parameters has a URL you can refer to it from, you just add:

GET [parametersurl]/validationresults

POST [paramatersurl]
body: {command:"activate"}

But again, that activate thing is RPC, not REST.

━╋う一瞬間旳綻放 2024-08-15 08:38:28

激活和验证要求是您尝试更改资源状态的情况。这与使订单“完成”或“提交”其他请求没有什么不同。有多种方法可以对此类状态更改进行建模,但我发现最有效的一种方法是为相同状态的资源创建集合资源,然后在集合之间移动资源以影响状态。

例如,创建一些资源,例如,

/ActiveParameters
/ValidatedParameters

如果您想让一组参数处于活动状态,则将该组添加到 ActiveParameters 集合中。您可以将参数集作为实体主体传递,也可以将 url 作为查询参数传递,如下所示:

POST /ActiveParameters?parameter=/Parameters/{Id}

使用 /ValidatedParameters 可以完成相同的操作。如果参数无效,则服务器可以向请求返回“错误请求”,以将参数添加到已验证参数的集合中。

The activate and validate requirements are situations where you are attempting to change the state of a resource. It is no different that making an order "completed", or some other request "submitted". There are numerous ways to model these kinds of state change but one that I find that often works is to create collection resources for resources of the same state and then to move the resource between the collections to affect the state.

e.g. Create some resources such as,

/ActiveParameters
/ValidatedParameters

If you want to make a set of parameters active, then add that set to the ActiveParameters collection. You could either pass the set of parameters as an entity body, or you could pass an url as a query parameter, as follows:

POST /ActiveParameters?parameter=/Parameters/{Id}

The same thing can be done with the /ValidatedParameters. If the Parameters are not valid then the server can return "Bad Request" to the request to add the parameters to collection of validated parameters.

皓月长歌 2024-08-15 08:38:28

我建议使用以下元资源和方法。

使参数处于活动状态和/或验证它们:

> PUT /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Content-Type: application/json
> Connection: close
>
> {'active': true, 'require-valid': true}
>
< HTTP/1.1 200 OK
< Connection: close
<

检查参数是否处于活动状态且有效:

> GET /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Connection: close
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Connection: close
<
< {
<     'active': true,
<     'require-valid': true,
<     'valid': {'status': false, 'reason': '...'}
< }
<

I would suggest the following Meta resource and methods.

Make parameters active and/or validate them:

> PUT /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Content-Type: application/json
> Connection: close
>
> {'active': true, 'require-valid': true}
>
< HTTP/1.1 200 OK
< Connection: close
<

Check if the parameters are active and valid:

> GET /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Connection: close
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Connection: close
<
< {
<     'active': true,
<     'require-valid': true,
<     'valid': {'status': false, 'reason': '...'}
< }
<
你不是我要的菜∠ 2024-08-15 08:38:28

看到 10 多年过去了,还没有答案真正说明如何在 REST 架构中设计 OP 中所要求的东西,我感到有点难过,因此我觉得现在有必要这样做。

首先,什么是 REST?!首字母缩略词 REST 或 ReST 代表“表述性状态传输”,并以某种表示格式定义资源状态的交换。表示格式与协商的媒体类型一致。在 application/html 的情况下,表示格式可能是在浏览器中呈现的 HTML 格式的文本内容流,可能是在应用某些样式表格式以将某些元素定位在某些位置之后。

REST 原则上是我们都知道的可浏览 Web 的概括,但其目标是所有类型的应用程序而不仅仅是浏览器。因此,根据设计,适用于 Web 的相同概念也适用于 REST 架构。诸如如何以“RESTful”方式实现某些内容之类的问题解决了如何在网页上实现某些内容,然后将相同的概念应用到应用程序层的问题。

基于网络的计算器通常可能从一些“页面”开始,该“页面”允许您在将输入的数据发送到服务器之前输入一些要计算的值。在 HTML 中,这通常是通过 HTML

元素来实现的,该元素教导客户端要设置的可用参数、要发送请求的目标位置以及发送请求时要应用的表示格式。输入数据。这可以看起来像这样:

<html>
  <head>
    ...
  </head>
  <body>
    <form action="/../someResource" method="post" enctype="application/x-www-form-urlencoded">
      <label for="firstNumber">First number:</label>
      <input type="number" id="firstNumber" name="firstNumber"/>

      <label for="secondNumber">Second number:</label>
      <input type="number" id="secondNumber" name="secondNumber"/>

      <input type="submit" value="Add numbers"/>
    </form>
  </body>
</html>

上面的示例 ie 指出有两个输入字段可以由用户或其他自动机填写,并且在调用提交输入元素时,浏览器负责格式化输入数据转换为 application/x-www-form-urlencoded 表示格式,该格式通过指定的 HTTP 请求方法(本例中为 POST)发送到上述目标位置。如果我们在 firstNumber 输入字段中输入 1,在 secondNumber 输入字段中输入 2,浏览器将生成一个firstNumber=1&secondNumber=2 的表示形式,并将其作为实际请求的正文有效负载发送到目标资源。

因此,向服务器发出的原始 HTTP 请求可能如下所示:

POST /../someResource
Host: www.acme.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Accept: application/html

firstNumber=1&secondNumber=2

服务器可以执行计算并以包含计算结果的进一步 HTML 页面进行响应,因为该请求表明客户端理解此格式。

正如 Breton 已经指出的那样,不存在“RESTful”URL 或 URI 这样的东西。 URI/URL 是它自己的东西,不应该向客户端/用户传达任何含义。在上面的计算器示例中,用户根本不关心将数据发送到哪里,只关心触发提交输入字段时发送请求。服务器应该已经提供了执行任务所需的所有信息。

浏览器也可能不知道该请求实际上是在向计算器提供一些输入参数,它也可能是某种订单表单,仅返回下一个表单表示以继续订购过程,或者是某种完全不同类型的订单表单。资源。在这种情况下,它只是执行 HTML 规范所要求的操作,而不会关心服务器实际在做什么。这个概念使浏览器能够使用相同的表示格式来执行各种操作,例如从您喜欢的在线商店订购一些东西、与您最好的朋友聊天、登录在线帐户等等。

某些元素的可供性,例如在提交输入字段的情况下通常呈现为按钮,定义您应该使用它做什么。对于按钮或链接,它基本上会告诉您单击它。其他元素可能传达不同的可供性。这种可供性也可以通过 link-relations 表达为即带有 preload 带注释的链接,基本上告诉客户端它已经可以在后台加载链接资源的内容,因为用户接下来很可能会获取此内容。当然,此类链接关系应该标准化或遵循 网络链接

这些是 Web 上使用的基本概念,也应该在 REST 架构中使用。根据“Bob 叔叔”Robert C. Martin 架构是关于意图< /a> REST 架构背后的意图是将客户端与服务器解耦,以允许服务器在未来自由发展,而不必担心它们会破坏客户端。不幸的是,这需要大量的纪律,因为很容易引入耦合或添加快速修复解决方案来完成工作并继续前进。正如 Jim Webber 在 REST 架构中指出的那样,作为服务提供商,您应该尝试设计一个 域应用程序协议类似于 70 年代基于文本的计算机游戏,客户将遵循该协议直到到达流程的末尾。

不幸的是,许多所谓的“REST”API 实际上所做的一切都不是这样。您会看到主要基于 JSON 的数据交换,这些数据在特定于 API 的外部文档中指定,通常很难动态动态集成。请求的格式也被硬编码到外部文档中,这导致大量实现将 URI 解释为 返回预定义类型,而不是使用预先协商的某种通用表示格式。这可以防止服务器发生更改,因为客户端现在期望接收预定义 URI 的特定数据格式(注意不是表示格式!)。这种自定义数据格式交换还可以防止客户端与其他 API 交互,因为“数据格式”通常适用于特定 API。我们从过去的 RPC 技术(例如 Corba、RMI 或 SOAP)中了解到这个概念,我们谴责这些技术在某种程度上是邪恶的,尽管 Peppol 最近再次转向它,用 AS4 替换 AS2 作为默认传输协议。

关于提出的实际问题,以 csv 文件形式发送数据与使用 application/x-www-form-urlencoded 表示或类似内容没有什么不同。 Jim Webber 明确表示,毕竟 HTTP 只是一个传输协议,其应用域是通过网络传输文档。客户端和服务器至少应支持 RFC 中定义的 text/csv 7111。该 CSV 文件可以作为处理媒体类型的结果而生成,该媒体类型定义了表单元素、用于发送请求的目标元素或属性以及用于执行配置上传的 HTTP 方法。

有几种媒体类型支持表单,例如 HTMLHAL 表单halformion九头蛇。不过,我目前还不知道有一种媒体类型可以自动将输入数据直接编码为 text/csv ,因此可能需要使用 IANA 的媒体类型注册表

我想完整参数集的上传和下载应该不是问题。如前所述,目标 ​​URI 并不相关,因为客户端仅使用 URI 来检索要处理的新内容。按营业日期过滤也不应该太困难。然而,这里服务器应该为客户端提供客户端可以简单选择的所有可能性。近年来,GraphQL 和 RestQL 不断发展,引入了一种类似 SQL 的语言,可以针对某个端点来获得过滤后的响应。然而,从真正的 REST 意义上来说,这违反了 REST 背后的理念,因为 a) GraphQL 即仅使用单个端点,这在某种程度上阻碍了缓存的最佳使用;b) 需要了解可用字段,这可能会导致引入客户端耦合到资源的基础数据模型。

激活或停用某些配置参数只需触发提供此功能的超媒体控件即可。在 HTML 表单中,这可以是一个简单的复选框或列表中的多行选择或类似类型。根据表单及其定义的方法,它可能会通过 PUT 发送整个配置,或者智能地了解已完成的更改,并仅通过 PATCH 执行部分更新。后一种方法基本上需要计算更新表示的变化表示,并向服务器提供将当前表示转换为所需表示所需的步骤。根据 PATH 规范,这必须在事务中完成,因此要么应用所有步骤,要么不应用任何步骤。

HTTP 允许并鼓励服务器在应用更改之前预先验证收到的请求。对于 PUT 规范指出:

源服务器应该验证 PUT 表示是
与服务器对目标的任何约束一致
不能或不会被 PUT 更改的资源。这是
当源服务器使用内部时尤其重要
与 URI 相关的配置信息,以便设置
GET 响应上表示元数据的值。当 PUT
表示与目标资源、来源不一致
服务器应该通过转换来使它们一致
表示或更改资源配置,或响应
带有包含足够信息的适当错误消息
解释为什么这种表示方法不合适。 409(冲突)
或 415(不支持的媒体类型)状态代码建议,
后者特定于 Content-Type 值的约束。

例如,如果目标资源配置为始终具有
“text/html”的内容类型和 PUT 的表示有一个
Content-Type 为“image/jpeg”,源服务器应该执行以下操作之一:

a.重新配置目标资源以反映新的媒体类型;

b.将 PUT 表示转换为与其一致的格式
在将资源保存为新资源状态之前对其进行分析;或者,

c.使用 415(不支持的媒体类型)响应拒绝请求
表明目标资源仅限于“text/html”,
也许包括指向不同资源的链接
新表示的合适目标。

HTTP 没有准确定义 PUT 方法如何影响对象的状态
源服务器超出了用户意图所能表达的范围
代理请求和源服务器响应的语义。 ...

总结这篇文章,您应该使用现有的媒体类型,该类型允许您向客户端介绍所需或支持的输入参数、发送请求的目标位置、要使用的操作以及媒体- 键入必须采用的格式的请求,或定义您自己的向 IANA 注册的请求。如果您想将输入转换为 text/csv 然后将 CSV 表示形式上传到服务器,则可能需要后者。验证应在将更改应用于资源之前进行。实际的 URI 不应该与客户端相关,除了确定将请求发送到哪里之外,因此可以由您(服务实现者)自由选择。通过遵循这些步骤,您几乎可以随时更改服务器端,并且如果客户端支持所使用的媒体类型,则客户端不会因此而崩溃。

I feel a bit sad to see that after more than 10 years there is no answer really stating how such a thing as requested in the OP could be designed in a REST architecture, hence I feel the need to do this now.

First things first, what is REST?! The acronym REST or ReST stands for "Representational State Transfer" and defines the exchange of a resource's state in a certain representation format. The representation format is tide to the negotiated media type. In the case of application/html the representation format may be a stream of HTML formatted text content that is rendered in the browser, probably after applying some stylesheet formatting to position certain elements at certain locations.

REST is in principle a generalization of the browsable Web we all know, though targets all kinds of applications and not only browsers. Therefore, by design, the same concepts that apply to the Web also apply to a REST architecture. A question like how to achieve something in a "RESTful" way resolves around answering the question how to achieve something on a Web page and then apply the same concepts onto the application layer.

A Web based calculator may usually start off with some "page" that allows you to input some values to calculate before sending the entered data to the server. In HTML this is usually achieved via HTML <form> elements that teaches a client on the available parameters to set, the target location to send the request to as well as the representation format to apply upon sending the input data. This can i.e. look like this:

<html>
  <head>
    ...
  </head>
  <body>
    <form action="/../someResource" method="post" enctype="application/x-www-form-urlencoded">
      <label for="firstNumber">First number:</label>
      <input type="number" id="firstNumber" name="firstNumber"/>

      <label for="secondNumber">Second number:</label>
      <input type="number" id="secondNumber" name="secondNumber"/>

      <input type="submit" value="Add numbers"/>
    </form>
  </body>
</html>

The sample above i.e. states that there are two input fields that can be filled out either by the user or by some other automata, and that upon invoking the submit input element the browser takes care of formatting the input data into a application/x-www-form-urlencoded representation format that is sent to the mentioned target location via the specified HTTP request method, POST in this case. If we enter 1 into the firstNumber input field and 2 into the secondNumber input field, the browser will generate a representation of firstNumber=1&secondNumber=2 and send this as the body payload of the actual request to the target resource.

The raw HTTP request issued to the server therefore may look like this:

POST /../someResource
Host: www.acme.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Accept: application/html

firstNumber=1&secondNumber=2

The server may perform the calculation and respond with a further HTML page that contains the result of the calculation, as the request indicated that the client understands this format.

As Breton pointed already out there is no such thing as a "RESTful" URL or URI. A URI/URL is its own kind of thing and should not convey any meaning to a client/user. In the calculator sample above a user simply isn't interested where to send the data to it is just interested in that upon triggering the submit input field the request is sent. All the required information needed to perform the task should already be given by the server.

A browser also might not be aware of that the request is actually feeding a calculator with some input parameters, it could as well be some kind of an order form that returns just the next form representation to continue the ordering process or some totally different kind of resource. It simply performs what the HTML spec demands in such a case and it couldn't care less what the server is actually doing. This concept enables a browser to use the same representation format to do all kind of things such as ordering some stuff from your preferred online shop, chatting with your best friends, signing into an online account and so on.

The affordance of certain elements, such in the submit input field case that is usually rendered as button, defines what you should to with it. In the case of a button or a link it basically tells you to click it. Other elements may convey different affordances. Such an affordance can also be expressed via link-relations as i.e. with preload annotated links that basically tell a client that it can already load the content of the linked resource in the background as the user will most likely grab this content next. Such link relations should of course be standardized or follow the extension mechanism for relation types as defined by Web linking.

These are the fundamental concept that are used on the Web and that should also be used in a REST architecture. According to "Uncle Bob" Robert C. Martin an architecture is about intent and the intention behind the REST architecture is the decoupling of clients from servers to allow servers to evolve freely in future without having to fear them breaking clients. This unfortunately requires a lot of discipline as it is so easy to introduce coupling or to add quick-fix solutions to get the job done and move on. As Jim Webber pointed out in a REST architecture you, as a service provider, should attempt to design an domain application protocol similar to a text based computer game of the 70s that clients will follow through until they reached the end of a process.

What plenty of so-called "REST" APIs unfortunately do in reality is everything but that. You see the exchange of mostly JSON based data that is specified in an API specific external documentation that is usually hard to dynamically integrate on the fly. The format how a request needs to look like are also hardcoded into the external documentation which lead to plenty of implementation interpreting URIs to return predefined typs instead of using some common representation format that is negotiated upfront. This prevents servers from changing as clients now expect to receive a certain data format (note not representation format!) for predefined URIs. This custom data format exchange furthermore prevents clients from interacting with other APIs as the "data format" is usually tide to a specific API. We know this concept from the past from RPC technologies such as Corba, RMI or SOAP which we condemn as somehow evil, even though Peppol moved to it again by replacing AS2 with AS4 as default transfer protocol as of recently.

In regards to the actual question asked, sending data as csv file is nothing different than using application/x-www-form-urlencoded representation or similar stuff. Jim Webber made it clear that after all HTTP is just a transport protocol whose application domain is the transfer of documents over the Web. Client and server should at least both support text/csv as defined in RFC 7111. This CSV file could be generated as a consequence of processing a media type that defines form elements, a target element or attribute to send the request to as well as the HTTP method to perform the upload of the configuration.

There are a couple of media types that support forms such as HTML, HAL Forms, halform, ion or Hydra. I am currently, though, not aware of a media type that automatically can encode the input data into text/csv directly hence one might need to be defined and registered with IANA's media type registry.

The upload and download of the complete parameter set shouldn't be an issue I guess. As mentioned before, the target URI is not of relevance as a client will just use the URI to retrieve new content to process. Filtering by business date should also not be to difficult. Here the server should however the client with all the possibilities the client simply can chose from. In recent years GraphQL and RestQL evolved which introduce an SQL like language that can be targeted at a certain endpoint to get a filtered response. However, in a true REST sense this violates the idea behind REST as a) GraphQL i.e. only uses a single endpoint which somehow prevents optimal usage of caching and b) requires the knowledge of available fields upfrong, which may lead to introducing a coupling of clients to the base data model of the resource.

Activating or deactivating certain configuration parameters is simply a matter of triggering the hypermedia controls that provide this affordance. In HTML forms this could be a simple checkbox or a multi-line selection in a list or that kind. Depending on the form and what method it defines it could then potentially send the whole configuration via PUT or be smart about the changes done and only perform a partial update via PATCH. The latter one requires basically a calculaton of the change representation to the one updated and feed the server with the required steps to tranform the current representation into the desired one. According to the PATH specification this has to be done within a transaction so that either all or none of the steps are applied.

HTTP allows and encourages a server to validate a received request upfront before applying the changes. For PUT the spec states:

An origin server SHOULD verify that the PUT representation is
consistent with any constraints the server has for the target
resource that cannot or will not be changed by the PUT. This is
particularly important when the origin server uses internal
configuration information related to the URI in order to set the
values for representation metadata on GET responses. When a PUT
representation is inconsistent with the target resource, the origin
server SHOULD either make them consistent, by transforming the
representation or changing the resource configuration, or respond
with an appropriate error message containing sufficient information
to explain why the representation is unsuitable. The 409 (Conflict)
or 415 (Unsupported Media Type) status codes are suggested, with the
latter being specific to constraints on Content-Type values.

For example, if the target resource is configured to always have a
Content-Type of "text/html" and the representation being PUT has a
Content-Type of "image/jpeg", the origin server ought to do one of:

a. reconfigure the target resource to reflect the new media type;

b. transform the PUT representation to a format consistent with that
of the resource before saving it as the new resource state; or,

c. reject the request with a 415 (Unsupported Media Type) response
indicating that the target resource is limited to "text/html",
perhaps including a link to a different resource that would be a
suitable target for the new representation.

HTTP does not define exactly how a PUT method affects the state of an
origin server beyond what can be expressed by the intent of the user
agent request and the semantics of the origin server response. ...

To sum this post up, you should either use an existing media type that allows you to teach a client about the required or supported input parameters, the target location to send the request to, the operation to use as well as the media-type the request has to be formatted in, or define your own one that you register with IANA. The latter might be necessary if you want to convert the input to text/csv and then upload the CSV representation to the server. The validation should occur before the changes are applied to the resource. The actual URI should not be of relevance to clients other than to determine where to send the request to and as such can be freely chosen by you, the service implementor. By following these steps you pretty much gain the freedom to change your server side at any time and clients will not break as a consequence if they support the used media-types.

逐鹿 2024-08-15 08:38:28

编辑: 事实上,URI 会阻止 GET 请求保持幂等性。


然而,对于验证,使用 HTTP 状态代码来通知请求的有效性(创建新的或修改现有的“参数”)将适合 Restful 模型。

如果提交的数据无效,并且必须在重新提交之前更改请求 (HTTP/1.1 状态代码)。

但这依赖于在提交时进行验证,而不是像在您的用例中那样推迟验证。其他答案对这种情况有合适的解决方案。

Edit: Indeed the URI would have prevented GET requests from remaining idempotent.


For the validation however, the use of HTTP status codes to notify the validity of a request (to create a new or modify an existing 'parameter') would fit a Restful model.

Report back with a 400 Bad Request status code if the data submitted is/are invalid and the request must be altered before being resubmitted (HTTP/1.1 Status Codes).

This relies on validating at submission time though, rather than deferring it as in your use-case. The other answers have suitable solutions to that scenario.

话少心凉 2024-08-15 08:38:28

在 REST 环境中,每个 URL 都是唯一的资源。你有什么资源?金融计算器确实没有任何明显的资源。您需要深入研究您所调用的参数并提取资源。例如,贷款的摊销日历可能是一种资源。日历的 URL 可能包括开始日期、期限(以月或年为单位)、期限(复利时)、利率和初始本金。有了所有这些值,您就有了一个特定的付款日历:

http://example.com/amort_cal/2009-10-20/30yrsfixed/monthly/5.00/200000

现在,我不知道您在计算什么,但您的参数列表概念听起来并不 RESTful。正如其他人所说,您的上述要求听起来更像是 XMLRPC。如果您尝试 REST,则需要名词。计算不是名词,而是作用于名词的动词。您需要扭转它,将名词从计算中剔除。

In a REST environment, each URL is a unique resource. What are your resources? A financial calculator really doesn't have any obvious resources. You need to dig into what you are calling parameters and pull out the resources. For example, an amortization calendar for a loan might be a resource. The URL for the calendar might include start date, term (in months or years), period (when interest is compounded), interest rate, and initial principle. With all those values, you have a specific calendar of payments:

http://example.com/amort_cal/2009-10-20/30yrsfixed/monthly/5.00/200000

Now, I don't know what you are calculating, but your concept of a parameter list doesn't sound RESTful. As someone else said, your requirements above sound more XMLRPC. If you are trying for REST, you need nouns. Calculations are not nouns, they are verbs that act on nouns. You need to turn it around to pull the nouns out of your calcs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文