【问题标题】:Rest api url design exceptionsRest api url 设计异常
【发布时间】:2021-08-13 06:58:31
【问题描述】:

我阅读了一些关于更正(干净)用于休息端点的 url 设计的文章和帖子。 无论如何,我想讨论或建议我有一些疑问和不清楚的情况。

情况

假设我们有一个服务,它有注册用户。管理员可以为每个用户附加自定义注释,其中包含一些文本。

我想被告知的问题只是CRUD端点,这可能是微不足道的问题。

我们将有 4 个相关的端点:


POST(创建)
根据一些指导方针,我们可能会设计如下 URL:
/users/{userId}/notes
并发送包含详细信息的有效负载。这里没有问题


获取(读取)
类似案例:
/users/{userId}/notes
作为响应,我们会收到附加到特定用户的注释列表。这里没有问题


更新(更新)
类似案例:
/users/{userId}/notes
作为有效负载服务器,接收带有所有 note 详细信息的 API 对象。
在这里,我有我的第一个疑问。由于我收到了包含userId: 值的note 对象- 我应该严格使用URL 模式吗? userId 在这种情况下是多余的。当然,我可以在PathVariable 和有效负载中接收该值,但这是正确的方法吗?同样的情况出现在许多其他CRUD's,这就是为什么我想知道“良好做法”
API 对象:

{
    "id": 1,
    "userId": 2,
    "text": "Some message"
}

DELETE(删除)
类似案例:
/users/{userId}/notes/{noteId}
事实上删除我只需要noteId 信息。我认为 - /users/notes/{noteId} 就足够了,但这对于 DELETE 操作意味着我会有不同的 URL。与UPDATE 的情况类似。


问题

我是否应该严格遵守 URL 命名约定并使用 /users/{userId}/notes?简单的 CRUD 操作有什么好的做法?

【问题讨论】:

    标签: api rest clean-architecture


    【解决方案1】:

    您应该查看Webber 2011

    在 REST 中,我们没有“端点”,我们有“资源”。您的资源模型实际上是一个文档集合,每个文档都有一个唯一标识符,可以读取 (GET) 和写入 (POST/PUT/PATCH)。

    您的域模型中的有用工作是一种副作用,当有人编辑您的资源时会发生这种情况。

    机器不关心我们对资源标识符使用什么拼写约定,因此我们通常选择一种对人类来说更容易的拼写;通常这意味着标识符与文档名称密切相关。


    由于我收到包含 userId: value 的注释对象,我是否应该严格使用该 URL 模式?

    是的。

    广义的观点(Webber 在上面链接的谈话中强调)是 HTTP 是一个应用程序协议;只要我们在请求/响应元数据中包含对正在发生的事情的正确描述,通用组件就可以完成有用的工作。

    特别是,应用程序具有缓存和cache-invalidation。如果您正确识别正在更改的资源,缓存可以自动使以前缓存的响应无效。

    这就是我们识别请求修改的特定资源的原因之一,而不是仅仅将我们的所有编辑发布到单个通用资源。


    我是否应该严格遵守 URL 命名约定并使用 /users/{userId}/notes?

    是的;实际上,这就像拥有一个包含每个用户的笔记的网页,管理员可以编辑该网页(添加和删除笔记)。

    【讨论】:

    • 感谢您的回答。它确实有助于理解正确的设计。我对你回答的最后一部分有疑问。如果我在系统中使用noteId globaly unique 或者它在每个用户的上下文中是唯一的,会有区别吗?我的意思是——如果我要一张 id = 100 的便条,我肯定只会收到一份文件,因为它是全球独一无二的。那么我是否应该仍然使用 /users/{userId}/notes/{noteId} 如果在 user 的上下文中枚举注释有区别吗?例如,noteId = 1 会有很多用户,而不是路径 /users/{userId}/notes/{noteId} 对我来说似乎是逻辑
    • REST 不关心您对 URI 使用的拼写约定,只要它们与 RFC 3986 中定义的生产规则一致。选择 URI 拼写是权衡取舍,例如“什么是最简单的”读取访问日志/浏览器历史记录?”和“链接表示应该使用相对分辨率吗?”
    【解决方案2】:
    • 由于这是一个固执己见的问题,因此没有一个单一的答案。
    • 但为了良好的设计,这是我更喜欢的,只要我可以为一个实体(如您的案例中的笔记)提供唯一 ID,它应该仅被视为一个独立实体。
    • 假设你需要玩实体 X,如果你选择X/{id},你只需要 X 的 ID,而不是 X 可能是其子级的所有事物的 ID,所以再次简单地依赖 X 的 ID 要简单得多然后依赖从最高父级到 X 的每个人的 ID。
    • 想象一下,如果您采用 users/{id}/notes/{id} 设计,那么将来您的笔记需要添加对 cmetslikes 的支持等等,在这种情况下,现在的网址将变成users/{id}/notes/{id}/comment/{id},这可能会继续下去,因为几乎所有东西都会通过某种逻辑连接到用户。
    • 另外,根据语言/框架构建路线,这些连接和嵌套的路径可能会很复杂,特别是对于其他团队成员而言。

    【讨论】:

      猜你喜欢
      • 2020-09-18
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 2021-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多