带链接的REST资源表示,与PUT和GET兼容



我被要求设计和实现一个RESTful API,并一直在研究最佳实践,但到目前为止,我对资源表示只有一个模糊的概念。我发现的大多数可用示例似乎都主要关注使用一系列get遍历连接结构的API客户端。

我看过:

http://www.restapitutorial.com/media/RESTful_Best_Practices-v1_1.pdf

http://www.youtube.com/watch?v=HW9wWZHWhnI

在其他在线资源中(我仅限于2个链接,抱歉不能列出全部)。它们都很棒,但并不能真正解决我的设计问题。

大多数最佳实践文档建议的两件事在我看来有点冲突:

1) REST服务应该将数据关系表示为资源之间的链接

2)来自客户端的"PUT"请求应该是一个完整的表示,在形式上与服务器上看到的表示相同。

在我看来,问题在于典型资源中的链接以及可能相当多的其他属性都是只读的,因此无法更新。显然,服务器应该期望它们保持原样,如果它认为客户端正在尝试更新它们,则返回错误。事实上,当我查看以JSON表示的典型资源时,它的大部分是逻辑上不能/不应该被替换的数据。例如

{
 "link": { "rel":"self", "href":"http://example/project/12345" },
 "team": {
    "link": { "rel":"self", "href":"http://example/project/12345/team" },
    "title": "The project team"
  },
  "title": "The Big Project"
}

在这里,最多只有两个标题文本可以在此资源上写入客户端(团队成员资格可以通过团队链接更改)。

那么,我是否应该要求PUT完全按原样包含所有的"链接"元素,这些元素是纯逻辑和只读的(注意,在示例中,团队不能被重新链接,因为资源将其定义为项目的团队-在这种情况下可以更改,但对于许多具有更严格的容器关系的资源类型,这并不适用)?

在REST中使用许多链接表示资源是否存在标准模式或反模式?我并没有被要求提供特定的REST变体,比如HATEOAS,尽管我倾向于尽可能地以理论上的"正确性"为目标。换句话说,如果"正式的"REST是期望客户端PUT整个资源、链接和所有内容,那么这可能就是我要做的。

一些支持GET和PUT的真实世界的复杂非叶REST资源的示例,因此必须处理这个问题,将非常感谢。当我搜索的时候,我得到了很多的意见,和许多例子显示如何很好地get工作…但到目前为止,我还没有看到一个记录良好的例子,显示一个PUT到任何东西,但一个平凡的叶子资源(即一个不包含任何链接,除了可能是一个自我引用)。

基本上,GET请求将返回序列化为已定义格式的资源,以及关于该资源的元数据(它们一起构成资源的表示)。当您返回一个表示时,它不需要包含元数据,也不需要采用与原始(或任何后续)GET请求相同的格式。然后,服务器将根据您提供的表示更新资源。

HTML中的一个例子是<head><body>元素,它们提供有关资源的元数据和资源表示;text/htmlapplication/x-www-form-urlencoded内容类型,以两种不同的格式传递资源表示,前者有元数据,后者没有元数据。当您在post后获取资源时,您不会期望收到application/x-www-form-urlencoded格式的数据!

我不确定你所说的"REST变体"是什么意思。只有一种REST。如果你指的是其他基于http的api,请不要称它们为REST。有关API样式的更多详细信息,请参见基于http的API分类。

最后,您要求提供非叶子PUT请求的示例。我不确定你所说的非叶子是什么意思,因为我能想到两种类型:

  1. 子资源

假设你有一个汽车目录,可以在/cars上找到。如果你决定要清除你所有的车,你可以选择DELETE /cars/1, DELETE /cars/2…等等,或者您可以选择具有空主体的PUT /cars或没有内容的数组。后者显然会更有效率。

子资源继续这个主题,让我们假设有一辆汽车,/cars/1,它是这样表示的:

{
  "model":"Model-T",
  "mfgr":"Ford",
  "colour":"black"
}

现在,您可能希望允许url访问这些字段,例如/cars/1/mfgr,这将返回Ford{"mfgr":"Ford"}。现在URL /cars/1代表一个非叶子资源。但是,将新的表示形式放入URL中仍然没有问题。因此,这也将更新子资源url的值。

最后,您可能想看看通过JSON传输超文本的HAL格式。

您应该按照您的媒体类型定义的方式使用"complete"表示。如果您正在设计自己的媒体类型,那么您的规范应该定义哪些部分是可变的,哪些是不可变的。例如,Shoji Catalog协议定义了一个旨在包含可变数据的"body"成员:

一般来说,当主体成员存在时,处理器应该期望体中呈现的值可能是可变的(通过一个HTTP PUT或POST,例如),并且应该期望外部的任何值主体成员是不可变的;这是(潜在的)可写的插入但不更新。服务器是免费的,当然允许或禁止资源的任何部分的可变性。但是a的存在"body"成员带有关于的可变性的强烈暗示成员内部和外部的数据

这不是一个标准(尽管它对我来说很明显很有用,我希望它成为一个标准)。请注意,服务器可以自由地对客户端发送的表示做任何事情;对任何HTTP服务器的最大要求是,它尝试执行客户端的意图(如果能够和允许的话)。它如何以及在多大程度上做到这一点确实是您的特定应用程序所关心的,这就是为什么您在任何规范中都找不到关于它的很多内容。

在实践中,我没有发现它有用的服务器来验证链接或其他不可变的部分表示;他们只是被忽略了。这可能会导致客户决定他们可以忽略这些。同样,在实践中,我没有发现这是一个问题。

最新更新