RESTful API设计。如果没有行,我应该返回什么?


50

我目前正在使用Slim Framework为社交网络编码API。我的问题是:当json结构中没有要返回的行时,最佳实践是什么?

可以说,此调用/ v1 / get / movies从表电影名称返回2行:

[
    {"name": "Ghostbusters"},
    {"name": "Indiana Jones"}
]

但是,然后我调用了/ v1 / get / books,该表中没有行。我应该只返回一个空结构吗?

[
]

...或者消息和错误代码会更好吗?

[
    "errors": {
        "message": "no matches found",
        "code": 134
    }
]

哪个更好的做法?(该API将在iOS和Android应用中使用)谢谢!


3
对我来说,这就像是一个问题,即零实际上是否是一个数量。
Scarridge

16
您的示例已损坏。您不能使用具有重复键的json对象。您正在寻找的是一个数组,即[{"name": "..."}, {"name":"..."}]
Martin Wickman

@MartinWickman抱歉,我只是修复了它。
Andres SK

8
@andufo,实际上,您没有……
avakar,

25
如果您的应用程序打算是RESTful的,那么动词/方法为什么“获得”作为端点URI的一部分?
user50849

Answers:


46

通常,我会将结果中的记录数作为元数据返回。我不确定这是否是正常的REST做法,但是它没有太多额外的数据,而且非常精确。通常有很多服务的分页,一次返回巨大的结果集是不切实际的。我个人恼火,当有分页对于小结果集。如果它是空的,回报number_of_records : 0和书籍作为空单/阵列books : []

{
    meta: {
        number_of_records : 2,
        records_per_page : 10,
        page : 0
    },
    books : [
        {id:1},
        {id:27}
    ]
}

编辑(几年后):马丁·威克曼的答案要好得多,这是为什么的“简短”解释。

处理分页时,请始终牢记内容或顺序更改的可能性。例如,第一个请求到来,有24个结果,您首先返回10。在那之后,插入了“新书”,现在您有25个结果,但是如果有原始请求,它将排在第10位。当第一个用户请求第二页时,他将不会获得“新书”。有一些方法可以解决此类问题,例如提供“请求ID”(应随以下API调用一起发送),然后从“旧”结果集中返回下一页,该结果集应以某种方式存储并绑定到“请求ID”。另一种方法是添加“自第一次请求以来结果列表已更改”之类的字段。

通常,如果可以的话,请尽力避免分页。分页是可以更改的附加状态,跟踪此类更改很容易出错,甚至更是如此,因为服务器和客户端都需要处理它。

如果您一次要处理的数据太多,请考虑返回“ id list”及其所​​有结果和该列表中某些部分的详细信息,并提供对资源的multi_get / get_by_id_list API调用。


1
呵呵,我想知道为什么这个选票不如另一个选票高。我更喜欢它,因为它不仅提供了一个空列表(应该是列表,对吗?),您可以在没有特殊条件的情况下盲目地进行迭代,而且还提供元数据作为一种说法,“不,我们没有这样做” t为您掩盖错误,实际上有0个结果。”
2013年

1
-1,因为books参数是一个对象,但是'books'隐含了多个,而多个则隐含了数组。元数据很酷,除了最终我希望所有的书都是一堆书对象。如果没有书,就给我排空
Charles Sprayberry

9
这样的问题是,添加“ number_of_records”不会提供更多信息,而只会增加冗余并增加复杂性。要发出错误信号,请返回适当的http代码+正文。
Martin Wickman

1
正如Izkata指出的那样,@ cspray图书就是清单,我的错字。
grizwako

2
@MartinWickman我不想使用额外的元数据来污染原始答案,但是根据我的经验,很多服务不会立即以“分页”的方式返回所有数据。
grizwako 2013年

105

您的示例已损坏。您不应该具有带有重复键的json对象。您正在寻找的是带有电影对象的数组,如下所示:

 [
    {"name": "movie1"}, 
    {"name": "movie2"}
 ]

这种方法也可以回答您的问题。当查询不匹配时,您应该返回一个空数组:

[]

另一方面,如果尝试使用来获取特定的电影资源GET api/movie/34并且该电影不存在,则在正文中返回404,并带有适当的(json编码)错误消息


1
+1这是根据的有效JSON json_xs
l0b0

15

如果这是JSON,则应真正考虑返回一个对象数组。这有很多优点,包括没有记录时它是一个空数组。

因此,当您有记录时,您将返回:

    [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]

当没有记录时,您将返回:

    [

    ]

14

如果您成功执行了操作,但是没有任何返回值,例如空的映射{}或空的数组,[]我希望使用204响应代码进行响应,则摘录自HTTP状态代码定义规范:

服务器已满足请求,但不需要返回实体,可能要返回更新的元信息。响应可以包括实体标题形式的新的或更新的元信息,如果存在,则应与所请求的变体相关联。

如果客户端是用户代理,则不应更改导致发送请求的文档视图。尽管任何新的或更新的元信息都应该应用于当前在用户代理的活动视图中的文档,但是该响应主要旨在允许输入操作而不会导致更改用户代理的活动文档视图。

204响应必须不包含消息正文,因此始终由标头字段之后的第一个空行终止。

本质上,当没有任何返回值时,我建议在HTTP上的RESTful应用程序中使用204。


4
我同意@avakar在这里对其他答案的评论。如果客户端尝试访问/ v1 / get / movies / 1,则如果没有可识别的电影,则应返回404。即使没有电影,/ v1 / get / movies也应返回200。但是204不适合,因为它用于输入操作。
imel96

7
此解决方案的另一个问题是,它通常在客户端中需要特殊的代码:如果响应为空列表,则可以像正常响应一样将其解析为JSON。如果响应为空,则JSON解析器可能会抱怨(因为一个空文档不是有效的JSON),因此客户端需要额外的代码来检查HTTP 204并跳过解析。
sleske 2014年

7
我认为这是对204意图的误读。204似乎不是针对预期内容但找不到任何内容的操作,而是针对成功且没有预期回报的操作。来自Wikipedia:“服务器成功处理了请求,但未返回任何内容。通常用作对成功删除请求的响应。”
XML

10

在创建标准化JSON API格式方面已经进行了大量的工作。

遵循该规范中的原则意味着,返回的所有资源都应有效地为“集合”(即使仅包含单个资源)。执行此操作将意味着您的呼叫/v1/get/movies将返回:

{
    "movies": [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]
}

您的调用/v1/get/books(返回零资源)将返回:

{
    "books": []
}

5

对于您的特定示例,我建议/ v1 / get / books返回带有空数组的HTTP 200。

如果我正在正确阅读您的文章,则您的API打算收集书籍。隐喻地讲,您有一个书架,一个DVD电影架以及可能没有在此提及的其他容器。因为您打算收集书籍,所以/ v1 / get / books是您的书架。这意味着那里有一个有效的资源-图书清单-在您的特定示例中碰巧是空的。

在这种情况下,我不建议返回HTTP 404的原因是书架仍然存在。目前没有任何书籍,但仍然是书架。如果不是书架-例如,如果API不想收集书籍,则使用 HTTP 404是合适的。但是,因为那里有一种资源,所以您不应发出信号说HTTP 404可以做到这一点。因此,我认为使用200为空数组(表示集合)更合适。

我不建议返回HTTP 204的原因是,这表明“无内容”是正常的情况:在此资源上执行此操作通常不会返回任何内容。这就是为什么通常将它用作对DELETE请求的响应的原因,例如:删除的性质通常意味着没有任何东西可以返回。当它用于使用If-Modified报头家族来响应请求时,情况也是如此:如果资源已更改,您只想要内容,但是没有,所以,我不会给您任何内容。

但是我认为,对于获取一个空但有效的集合,HTTP 204没有任何意义。如果集合中有项目,则正确的表示将是该数据的数组。因此,当那里没有数据(但集合有效)时,正确的表示形式是空数组。


5

您真的应该只做两件事之一

返回200 (OK)状态码和主体中的空数组。

或返回204 (NO CONTENT)状态码和否响应主体。

对我来说,选项2在技术上似乎更正确,并且符合REST和HTTP原则。

但是,对于客户端来说,选项1似乎更有效-因为客户端不需要额外的逻辑来区分两个(成功的)状态码。由于它知道它将始终接收一个数组,因此只需检查它是否没有,有一个或多个项目并进行适当处理即可。


3

我已经在生产环境中看到了这两种情况。您选择哪一种取决于谁将使用该API。如果他们想知道列表为什么为空,或者要确保列表真正为空,并且在检索列表时没有发生错误,则应该附加“错误”对象。如果他们不在乎,则返回一个空列表。我会采用第二种方法,因为它比第一种覆盖了更多需求。


3

由于您正在构建RESTful API,因此要考虑的第一件事是返回适当的响应代码。较古老的404是用于传达请求已正常通过但当前无法使用所请求资源的更合适的响应代码。

如果您以始终返回明智的响应代码的方式设计API,则可能在找不到资源时甚至不需要返回正文。话虽如此,返回尸体,尤其是人类可读的尸体,不会受伤。

这里没有“最佳实践”,您的两个示例都是任意的,只需选择一个并保持一致即可。开发人员讨厌惊喜,如果在没有电影的情况下/v1/get/movies回报{},那么我们希望在没有演员的情况下/v1/get/actors也能回报{}


1
返回404确实是正确的事情,但可惜没有人真正做到这一点-包括我自己。
RibaldEddie

1
如果您有复杂的响应,并且其中只有一部分为空,则返回404会使用户感到困惑。
devnull

5
我不同意404讯息。一个404我会解释为“资源不存在”,并担心我的URL或其他内容有问题。如果我要求提供电影列表并获得404,我会认为根本没有电影资源。“ 204 No Content”可能更合适。
thorstenmüller'13

8
好吧,“没有身体”的东西会杀死它。但是:“状态代码4xx类旨在用于客户端似乎已出错的情况。”。但是客户端没有错误。因此404错误信息。在没有尸体的情况下发送204,或者说没问题,然后发送一个空列表。
thorstenmüller'13

9
您要的是图书清单,返回404表示该清单不存在,不是空的。对我来说,返回200和一个空列表似乎是唯一合理的选择。
阿瓦卡

1

我认为答案并不严格。

在真实的REST场景中,nirth提供的答案应该是最好的。正文响应应为空,并且http状态码:204;资源确实存在,但当时“没有内容”:为空。

REST HTTP_Status_Codes


1

我建议使用200 +空数组,因为它可以简化API所有客户端的处理。200 +数组表示“我返回了那里的所有数据”。无论是传递数据的代码还是处理数据的代码,项目的数量都是无关紧要的。

每个其他状态代码都需要由服务器正确记录并正确交付,并由客户端正确处理,我们都知道这种情况发生的可能性。

有建议返回状态204 +空的身体。这意味着你强迫 一个客户端进程状态204正确。此外,您强迫他们处理非JSON回复!我希望每个人都意识到,仅因为请求获得了答案,并不意味着当使用http时答案就来自服务器,而只是检查响应是否为JSON即可处理许多情况。


0

我会“取决于”。

如果零是合理的结果,则返回空列表。例如,如果您想让所有员工都称为“ bob”,那么“ none”是相当合理的结果。如果不是预期的结果,则返回错误。例如,获取您所雇用人员的街道地址的历史列表。他们必须居住在某个地方,因此没有结果可能是错误,而不仅仅是正常情况。

我敢肯定,您可以与我的示例的细节争论,但是您明白了...


0
  • 首先,get在您的URL中不是RESTful的,HTTP方法隐含了GET。
  • 如果您需要类似的集合,则GET api/movies返回200 OK带有空数组的[]
  • 如果您要请求的特定电影GET api/movies/11ID 在哪里)并且不存在,请返回404 Not Found

为什么?您正在请求资源。当您请求集合时,资源本身(集合)存在。因此,a 404是错误的。但是,如果您请求的特定电影不存在,则请求的资源不存在,并且必须返回404


-2

如果返回的是JSON,则最好始终返回计数和错误消息,并且最好返回一个布尔值,该布尔值指示是否存在错误或不存在,这是我在每个行列表中返回的标准三个meta值。

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.