RESTAPI:当资源存在但已过期时,什么是正确的响应格式和状态代码



让我们假设我们有资源Employee。员工看起来是这样的(从实体和DB的角度来看):

{
id: 123,
name: "John Doe",
// more props here
workPermitExpireDateUTC: "1999-06-30 00:00:00"
}

当我们查询所有员工时,我们希望显示飞行中计算的附加标志isExpired

GET: /api/employees:

// HttpStatuCode: 200
[
{
id: 123,
name: "John Doe",
// more props here
workPermitExpireDateUTC: "1999-06-30 00:00:00",
workPermitExpired: true // calculated on a fly, based on system clock
},
{
id: 456,
name: "George Smith",
// more props here
workPermitExpireDateUTC: "2025-06-30 00:00:00",
workPermitExpired: false // calculated on a fly, based on system clock
}
]

当我查询单个未过期员工时

GET /api/employess/456我希望得到带有员工数据的200 Response——这是显而易见的。

然而,如果我们考虑过期员工,我不想发送所有数据,因为客户不需要知道。所以我的想法是这样返回:

GET: /api/employees/123:

// HttpStatuCode: 200
{
id: 123,
workPermitExpired: true,
errorMessage: "Employee work permit expired"
}

但感觉不对,因为200响应不应该根据资源id具有不同的结构。

这样的urlGET: /api/employees/123/non-expired怎么样?如果未过期,则返回200,如果过期,则返410

当资源存在但已过期时,正确的响应格式和状态码是什么?

在REST中需要理解的一件重要的事情是,我们的API是一个门面,它被故意设计成使我们的域看起来像web上的其他所有愚蠢的文档存储,因此所有通用web工具";只是工作";。

另一种说法是:HTTP是通过网络传输文档领域中的一种应用程序。当我们构建REST API时,我们要做的是将域协议调整为与客户端交换文档的语言。

状态代码和标头属于transport-documents-over-a-network域。

GET: /api/employees/123

对此的正确响应在很大程度上取决于我们是否有该资源的当前表示(这是运输文档领域的一个问题)。我们的域中该表示的语义真的没有进入其中。

如果我们有资源的当前表示,那么这是fine

200 OK
Content-Type: application/json
{
"id": 123,
"workPermitExpired": true,
"errorMessage": "Employee work permit expired"
}

当我们无法满足提供当前资源的请求时,我们通常会使用状态代码,向通用组件指示响应主体描述的是错误情况,而不是资源的表示。

404 Not Found
Content-Type: application/json
{ "error": "Who is 123?" }

感觉不对,因为200响应不应该根据资源id有不同的结构。

右。这通常转化为更仔细地定义您的模式。如果您希望在表示中打开和关闭某些字段,那么您的模式定义需要将这些字段描述为可选字段。例如,我们可以描述一个";有效许可证";模式和一个";过期许可证";模式(在不同的键下),具有客户端应该期望其中一个,但不能同时期望两者的约束。

另一种可能性是对不同的表示使用不同的内容类型。RFC 6838是您寻找细节的地方,但粗略的概述是,我们将定义两个不同的模式,然后为每个模式分配一个不同的内容类型

  • application/prs.maciej活动许可证+json
  • application/prs.maciej过期许可证+json

CCD_ 11>告诉通用目的消费者;只是";json文档,但熟悉您的特定媒体类型的消费者将有更具体的理解。

RFC7807是这种方法的标准化演示,其中字段名称的特定语义被编码到json文档中,媒体类型application/problem+json告诉通用组件真正发生了什么

您可以在application/merge-patch+json和application/json-patch+json中看到类似的想法。

从技术上讲,过期员工与员工的资源类型不同,例如

class ExpiredEmployee extends Employee

所以CCD_ 13将是合适的,因为您没有返回CCD_。您正在返回一个ExpiredEmployee

如果客户正在寻找员工,他们可能不在乎过期的员工,因为从技术上讲,他们不是员工?所以主要的url是:

未过期员工的GET /api/employess/456

您可以按照业务思路来设计URL。为什么有人想找到过期的员工?它们需要未过期吗?如果他们已经过期,为什么他们仍然被视为员工?如果客户的主要业务线是与员工合作,那么为过期员工设置一个单独的资源端点似乎是合适的,因为可能会有一个独立的业务流程来为他们工作。

如果客户不希望员工过期,那么返回的对象可能会让他们感到困惑。也许一个单独的业务线端点适合过期员工:

GET /api/employess/expired/456适用于过期员工

大概是因为寻找456的人已经知道他们已经过期了,想改变他们的状态?

最新更新