代码之家  ›  专栏  ›  技术社区  ›  Remus Rusanu

集合、项、动词和REST接口设计:POSTs应该返回什么?

  •  1
  • Remus Rusanu  · 技术社区  · 16 年前

    我正在设计一个REST接口,我对insert/update/delete动词应该返回什么(作为响应的内容)感到困惑。考虑一下 Invoice 实体,可在 api/invoices :

    • GET /api/invoices 返回发票列表
    • GET /api/invoices/123 返回ID为123的发票
    • POST /api/invoices 添加新发票(服务器上生成的ID)
    • POST /api/invoices/123 更新ID为123的发票
    • DELETE /api/invoices/123 删除ID为123的发票

    很明显前两个方法应该返回什么,但是insert/update/delet方法呢?一个显而易见的答案是 add 应返回新创建的项(即与GET/api/invoices/id完全相同的响应), update 应该返回更新的项(同样,与GET相同)并且 delete 可能不会返回任何内容(空内容)。这一切都有道理,而且是一致的。

    但我的问题开始于考虑那些不像发票实体那么简单的项目。例如,考虑 添加 请求不仅添加了项,而且实际上还需要返回有关添加操作的一些额外信息:项已被接受(成功),项是重复项(信息成功),项已被忽略(信息成功,我将不详细说明原因),项已被拒绝(失败)。另外,在我的例子中,还有一些额外的信息我想返回,比如为bucket预先设置的“response”信息进入新添加的条目。我考虑过将所有额外的信息放在http头中作为带外信息(比如200范围内的额外状态代码,甚至是自定义头),但这是一种攻击,而且“响应”部分实际上可以比项本身更大。所以现在我在考虑 添加 动词返回一个全新的类型,一个包含add信息的项(状态、响应、新项的ID,以及整个新项)。这当然能完成任务,但我怀念以前的对称性。

    这是一个好的做法(当添加“foo”类型的项目时,返回的是“bar”类型)还是我将在6个月后回顾并拔出头发,因为我让猫从包里出来?如果我坚持使用“any access on foo returns foo,including add”,那么客户端将不得不在“add”操作之后进行额外的调用,以检索它真正感兴趣的信息(即“response”)。

    2 回复  |  直到 16 年前
        1
  •  1
  •   S.Lott    16 年前

    你的答复应该相当复杂。它不应与入站请求匹配。我们使用JSON,除了对象之外,我们还有一些附加信息。

    典型反应:

    [{ "ID": the generated ID, "TYPE": the actual class name, "OBJECT": { the object } }]
    

    POST应该返回创建的对象。如果您有额外的信息(这不是一个好主意),您可以在响应消息中携带这些信息。

    PUT应该返回更新的结果。

    DELETE和GET一样,只能返回一个状态。

    状态中的额外信息不是黑客——这就是状态代码如此开放的原因。

    • 项目已接受(成功)-状态为200 OK

    • 这个项目是一个重复的(成功与信息)-我不确定你会有什么可能的信息以上和超过最终创建的对象,但这是一个地方为20倍-确定与信息状态。

    • 该项被忽略(信息成功,我不详细解释原因)-这是模棱两可的。我不会称之为成功,我会称之为40倍忽略。如果你不能详细说明原因,你可以称之为20倍忽略。

    • 项目被拒绝(失败)。这是一个普通的老40X拒绝消息。

        2
  •  0
  •   D.Shawley    16 年前

    一个可以考虑的选择 POST 返回是让它返回 额外的 信息和指向新创建对象的链接。在返回相同的 GET 将返回并返回一个完全不同的实体。