如何定义我的 REST API?

How can I define my REST API?

我有 3 个模型:tournamentchampionshipcompetitor:

因此,要列出所有锦标赛的所有参赛者,URL 是:

GET https://base.com/tournament/{slug}/competitors

但是要加一个参赛者,是和冠军有关的所以:

POST  https://base.com/championships/{id}/competitors

对于同一个模型,两个动词(GET 和 POST)有不同的 URI 可以吗?否则,我该怎么办?

我爱上了:

POST  https://base.com/tournaments/{slug}/championships/{id}/competitors 

没有必填字段。

Is it ok that for the same model, two verbs (GET and POST) has differents URI?

这可能会给 API 消费者造成混淆,因此我建议您使用相同的 URI。


请记住,Roy T. Fielding 的论文 chapter 5 中描述的 REST 架构风格为构建在顶层的应用程序定义了一组约束这样的架构。但是它没有关于 URI 必须是什么样的。

Martin Fowler 撰写的 popular article 中的示例解释了 Leonard Richardson 定义的模型 建议 一个看起来友好且易于阅读的 URI 结构。虽然它可能是理想,但对于 REST 应用程序来说并不是强制性


您可以采用许多有效的方法。如果竞争对手需要锦标赛存在,而锦标赛需要锦标赛 存在,你可以这样表达 hierarchy 使用:

/tournaments/{slug}
/tournaments/{slug}/championships/{id}
/tournaments/{slug}/championships/{id}/competitors/{id}

但最后一个URI可能会被认为太长,可能难以记住。所以你可以简单地拆分它,然后你不需要发送很多参数:

/tournaments/{slug}
/championships/{id}
/competitors/{id}

如果您需要执行任何过滤,您可以使用 query parameters。例如:

/championships/{id}?tournament={slug}

提醒:REST 不关心 URI 的拼写方式

Is it ok that for the same model, two verbs (GET and POST) has differents URI? Otherwise, how should I do?

没关系,但会产生一定的费用。

让我们回顾一下菲尔丁 (2008) 所说的话

REST is intended for long-lived network-based applications that span multiple organizations. The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction.

菲尔丁在他的论文中确定的复制方式之一是 the cache; he goes on to add that style to his definition of REST

In order to improve network efficiency, we add cache constraints to form the client-cache-stateless-server style.... Cache constraints require that the data within a response to a request be implicitly or explicitly labeled as cacheable or non-cacheable. If a response is cacheable, then a client cache is given the right to reuse that response data for later, equivalent requests.

在 HTTP 中,缓存的语义在 RFC 7234; Section 4.4 describes invalidation 中定义。

A cache MUST invalidate the effective Request URI (Section 5.5 of [RFC7230]) as well as the URI(s) in the Location and Content-Location response header fields (if present) when a non-error status code is received in response to an unsafe request method.

这意味着通过 generic 客户端的通信,对您的协议的细节一无所知,可以根据请求中的元数据使他们陈旧表示的本地副本无效和响应。

(在过去,当我们没有加密所有流量时,这是一个更大的问题;但它仍然适用于 (a) 客户端的本地缓存和 (b) 位于客户端前面的缓存反向代理领域模型)。

就REST而言,URI是不透明的;

之间没有根本关系
/A
/A/B
/A/B/C
/A/B/D
/A/E

因此,如果缓存发现 /A/B 应该无效,他们可以这样做,但他们不会对其他 URI 做任何事情。

对于 PUT、DELETE、PATCH——这些方法的语义非常特定于有效请求 URI。

如果您将相同的方法应用于 POST,那么您将“免费”获得缓存失效。

浏览一个简单的例子;想象一个网站,我们有

GET /superCoolResource
GET /superCoolResource/editForm

我们想在 /superCoolResource 中引入一些更改,因此我们加载编辑表单并提交....

POST ...?

如果我们 POST 到 /superCoolResource/editForm,那么我们告诉客户端 表单 的缓存副本应该被重新加载,如果 POST 成功。但这可能不是我们想要的——更有可能的是表单保持不变,而 /superCoolResource 是发生变化的东西。这意味着我们可能想让 /superCoolResource 成为目标 URI

GET /superCoolResource/editForm

200 OK

... <form action="/superCoolResource" method="POST"> ....

神奇的是,当 POST 成功时,客户端的缓存、源服务器的缓存和任何参与对话的中间缓存都知道驱逐它们的 /superCoolResource 的旧副本。