RESTful API代表没有东西


18

想象一下一个API,以确定一个人是否选择了他们的精神动物。他们只能有零个或一个精神动物。

目前:

/person/{id}/selectedSpiritAnimal

当他们选择了动物时,返回http 200, {selectedAnimal:mole}

但是当他们没有选择时,它将返回http 404。

这使我的精神动物不满意,因为我们正在表示一个有效的域问题-尚未选择精神动物-作为HTTP错误。

另外,作为一家公司-erm Sprit-Animal-Hampers-R-us,我们想知道某人何时没有选择,以便我们提示他们。

什么是更好的回应:

HTTP 200和 {selectedAnimal:null}

甚至更明确

HTTP 200和 {selectedAnimal:null, spiritAnimalSelected: false}

还是返回404更好?因为很像this image has not yet been uploaded在线查看图像时将是404。this person has not selected a spirit animal可能是404


该问题已被提议作为重复项,但是当应用程序配置为不允许该URL表示更改时,该问题解决了一个其他有效的URL。

而在这里,我正在研究在没有资源的情况下有意义的代表资源的方式。也就是说,客户端请求URL是有效的,并且响应是您已成功请求表示没有东西的资源。

因此,这不是“业务逻辑”,而是情况下缺少某物有意义(可能是因为我的许多同事都认为404仍然正确),但是我不确定如何将其映射到规格


很难选择答案。我在这里的谈话和正在进行的工作中多次改变主意。

在这里为我解决的问题是,规范指出4xx是客户犯错的时间。在这种情况下,已告知客户端期望来自selectedSpiritAnimal url的响应,因此不会出错。

我的同事之间的共识是,这是API设计错误的征兆

最好只请求/ person / {id}并返回该人的一组链接关系...那么如果没有给您/ selectedSpiritAnimal链接(当一个人没有选择时),但是您不管怎样都称它为404才有意义。或者您实施部分响应并让/ person / {id}返回更完整的文档,除非客户端请求数据的子集


5
您尚未说明为什么会认为返回404是一个问题。从域的角度来看,您不知道收到的是客户端层提取的404还是200。
Vincent Savard

14
还是最好返回204无内容?
Paul D'Ambra

6
我想我对404的担心消除了配置更改的歧义,该配置更改从没有精神动物的人身上引入了错误的URL模板
Paul D'Ambra

2
@ PaulD'Ambra对于它的价值,我不会使用无内容。自XmlHttpRequest以来,我还没有看到Javascript在前端以这种方式处理HTTP代码。但这当然是有效的。
布兰登·阿诺德

Answers:


24

对于这种情况,HTTP 4xx代码可能不是正确的选择。您声明精神动物为零是有效状态,API路由person/{id}/selectedSpiritAnimal将说明人是否id有一个。

当客户端在请求中做了一些不正确的情况时,将保留HTTP 4xx响应(请参阅w3的原始规范档案)。但是,无论人id是否有精神动物,客户都在发出有效的请求。

因此,我倾向于在响应中使用正确格式的JSON正文和HTTP 2xx代码来获取第二种解决方案。

现在,如果您收到这样的请求,结果发现人员id不存在,那么使用4xx代码更有意义。


17
“ HTTP 4xx响应保留给客户端在请求中做不正确的情况”。在对规范进行权威声明时,请参考实际的HTTP规范,而不是(a)建立在该规范之上的框架,或(b)随机博客文章。
埃里克·斯坦

5
@EricStein我确实对此感到有些懒惰;感谢您的批评。更新。
布兰登·阿诺德

1
我觉得这里的RFC链接有点冲突。一方面4xx部分说cases in which the client seems to have erred,但另一方面404直接说The server has not found anything matching the Request-URI。您可以考虑请求不存在客户端错误的内容。我了解此人不存在vs子道具不存在,但这可以表示为响应消息。204也似乎相关,因为该实体存在,但没有子属性的内容。
shortstuffsushi

1
客户做错了什么;它不存在时向用户请求了选定的精神动物。这就是404的意思……您要的是不存在的东西。
安迪

5
当我的浏览器向softwareengineering.stackexchange.com/questions/unicorn发出请求时, 这是一个有效的请求,但我仍然收到404(ID恰好是“ unicorn”的问题)。
user253751 '17

24

让我向您介绍理查森成熟度模型

您的问题是您将两个资源表示为一个,实际上您应该拥有两个具有超媒体指示关系的资源。使用超媒体来描述关系是Rest的辉煌3级。

您的人应该住在URI下,/person/{id}而动物应该住在URI 下/spiritanimal/{id}。该人应通过使用动物链接来表明它有精神动物。

假设有一个叫Bob的人,他的ID为123,是独角兽精神动物。

GET /person/123

会回来;

{
  "name": "Bob",
  "links": [
    {
      "rel": "spiritanimal",
      "uri": "/spiritanimals/789"
    }
  ]
}

现在,任何阅读123人的人都将知道他们有一只精神动物,并且拥有URI,可以在其中获取更多信息。

GET /spitiranimal/789

可能会回来

{
  "type": "Unicorn"
}

现在让我们想象一个叫Fred的人,他的ID为456,并且没有精神动物。

GET /person/456

会回来;

{
  "name": "Fred",
  "links": [
  ]
}

现在,任何读456人的人都会知道,他们没有灵性动物,因为没有联系。无需使用任何HTTP状态代码来表示缺少关系。


1
只是增加了一个问题,鉴于具有更改api的能力,某种程度的HATEOAS可能是正确的解决方案。这就是一个很好的例子
Paul D'Ambra

1

这是获取精神动物的合适网址;因此,404错误是不合适的。404用于表示技术问题,而不是逻辑问题。

适当的解决方案是返回http 200和 {"selectedAnimal": null}

您应该有一个单独的 web /person/{id}/hasSelectedSpiritAnimal方法返回{"isSpiritAnimalSelected": false}。在后台,它可能会或可能不会进行相同的方法调用,如果为null,则仅返回false,但这取决于它来决定,而不是由消耗代码决定。

最好避免在没有令人信服的理由的情况下将多个查询组合成一个Web方法,即使查询紧密相关。


1
您能否解释一下为什么您认为这是合适的解决方案?当没有数据要返回时,我毫无意义地返回数据。我同意您的观点,因为URL很好,所以404没有意义,因此204对我来说似乎最有意义。
Vincent Savard

2
@VincentSavard状态代码比json响应更难处理,并且更适合技术问题,而不是传达域信息。
TheCatWhisperer

2
204:无内容的空身体。一切都很清楚,不言自明。无需进一步争论。总而言之,当没有明确的设计模式时,SE应当选择一种,根据需要弯曲并提供文档。无需返回带有204响应的主体。
formixian

2
@formixian ...如果要创建bjson / tcp api而不是json / http,在这种情况下将返回什么?在我看来,依靠http代码似乎不必要地将api的结果绑定到其http实现。
TheCatWhisperer

2
@VincentSavard When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"没有内容意味着没有内容。即:它返回“”。这两个根本不相似。“精神动物当前未归档” 与“” 有很大不同。
Shane

1

端点代表的不仅仅是动物。这是动物还是动物这是一个最好用Optional/ Maybe/ Nullable/等表示的值。

因此合法值(如200 OK)可能是:

  • {'animal': <some animal>, 'selected': true}
  • {'animal': null, 'selected': false}

我可以想象该DELETE方法在应用于端点时可以再次设置'selected'false,即未设置选定的动物。

当然,您可以将'selected'密钥放在此处,仅为了说明而显示。字符串vs null足以区分。


0

您应该使用404。

404(未找到)状态代码表示原始服务器未找到目标资源的当前表示形式

RFC7231

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Mon, 25 Sep 2017 00:00:00 GMT

this person has not selected a spirit animal

由于您是在编写程序界面而不是人机界面,因此404文本是可选的。

我之所以这样,是因为我尽可能地喜欢标准协议。HTTP有一种表示不存在的方式,这就是我要使用的方式。

编辑:假设您添加了一个功能,用户可以选择是否共享他们的精神动物,而没有人共享。您会返回200 OK null还是200 OK "Unauthorized?还是使用标准的401未经授权/ 403禁止使用?这似乎直接类似于不首先选择一个。


另外,如果要使用200 OK + JSON,则应返回null

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

null

保持清洁。仅在必要时创建更多包装。


2
该数据发现,但。只是数据是null(没有值)而已。这与客户端请求不存在用于保存值的插槽的客户端不同。您不建议AttributeError在值恰好为时在Python中抛出None;这将使该界面不切实际并且不必要地难以使用。更为实用的是,许多HTTP客户端API可能会将404转换为该语言的标准错误处理机制(错误代码,异常,错误类型),这意味着您必须抑制无关的错误。
jpmc26 2015年

@Paul Draper在规范中向上滚动一点,您会看到它对HTTP 4xx进行了概括性声明:“ 4xx类状态码用于客户端似乎出错的情况。” 行动人士明确指出,没有精神动物是API应该考虑的有效状态。tools.ietf.org/html/rfc7231#section-6.5
Brandon Arnold

那么,您如何区分指示请求的资源不存在(即未选择动物)和客户端请求的路径无效(即/person/{id}/selectedSpritAnimal观察中的输入错误Sprit)之间的区别。
sampathsris

1
无论意图如何,404严格表示未找到资源。如果selectedSpiritAnimal是资源,并且不存在,则无需进行任何操作,并且404是合适的。但是,如果客户想知道是否选择了一种精神动物,则服务器应公开另一种资源/person/{id}/isSpiritAnimalSelected,该资源将告诉客户是否选择了一种动物。在我看来,在读取文件之前测试文件是否存在的经典示例相同。只需读取文件并处理抛出的ENOENT错误。
aaaaaa

1
@PaulDraper关键不是资源是否存在。关键是HTTP 4xx代码用于调用者错误使用API​​的情况。Op指出/person/{id}/selectedSpiritAnimal即使不存在精神动物也要使用。这意味着在这种情况下使用HTTP 4xx是不正确的。Op还正确地指出这可能是不良API设计的味道。
布兰登·阿诺德
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.