【问题标题】:RESTFul media type inheritanceRESTFul 媒体类型继承
【发布时间】:2014-09-11 09:14:01
【问题描述】:

我对 REST 完全陌生。我在工作中帮助实现了一种称为 REST 的东西,但它违反了很多规则,以至于很难将其限定为 REST。我想遵循 HATEOAS 指南,剩下的问题是关于媒体类型及其规范的文档。即当一种媒体类型实际上是另一种媒体类型的扩展时。

例如,我决定使用“application/hal+json”作为基本媒体类型。用户将收到的所有内容都将是一个带有一些附加字段的 HAL blob。我不想只将我的媒体类型称为“应用程序/hal+json”,在我看来应该有更多信息可用,但我希望清楚的是,除了额外的字段之外,这就是它们的含义那是我的数据。此外,我的系统最终会在请求(不会是 HAL blob)和响应格式中继承其中的一些字段。例如,通用的“用户”类型可能只有一个用户 id 和名称,而像“学生”或“教师”这样的扩展将有不同的附加字段。

在媒体类型本身的某个地方表示此扩展是否有意义?人们通常会在他们的 HATEOAS 文档链接中记录这种关系吗?如果是这样,这里的总体趋势是什么?我希望我的 API 易于使用,因此认为它应该遵循可用的规范。

【问题讨论】:

  • 你的问题不是很清楚。您是否在问“学生”媒体类型没有“用户”字段而是引用包含这些字段的“用户”资源是否有意义?

标签: rest hateoas media-type


【解决方案1】:

关于您转向真正的 RESTful 架构,我想指出几点。

首先,RESTful API 必须执行内容协商。说你的基本类型是 hal+json 似乎很奇怪。听起来你想要像 parent+hal+json 或者 hal+json;type=parent 这样的类型。这意味着您的客户必须专门了解这些类型……这不是很 RESTful,因为它只是一个本地实现。这在现实世界中很好……你可以这样做……几乎每个人都这样做。

要成为真正的 RESTful api,您必须为其他内容类型提供类似的支持......这可能会变得混乱。

现在专门针对 HAL,您可以使用两件事,以便您的客户可以“发现”他们返回的数据类型。一个是 CURIE,另一个是 Profiles https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-06#section-5.6 我认为 Profiles 更适合您在这里所追求的,因为它允许您记录将要检索的资源的约定和约束。

但也不要指望居里。已经有很多定义的语义。您的模型可能适合 http://schema.org 集合之一,然后您可以使用它们的链接关系,客户端应该知道发生了什么。

如果您真的想对资源的语义进行大量控制...您可能希望查看 http://json-ld.org/ 及其 @context 概念。

在我看来,这是一个例子非常少的领域,尤其是对于 HAL。我还没有见过足够聪明的客户端在运行时解析和关心语义。我认为重要的是,当有人在构建可用信息的客户端时,他们可以弄清楚学生是一个人。有一天,构建客户端的东西将是客户端生成器代码,它将使用该信息为您构建一个很好的客户端对象模型。

TL;DR 如果您坚持使用 HAL,请使用 CURIE 和配置文件来获得您想要的。

【讨论】:

    【解决方案2】:

    这个问题是一个非常开放的讨论,它实际上取决于不同的工程师如何解释 REST 标准和最佳实践。尽管如此,作为一名在 REST 服务开发方面有足够经验的软件工程师(并且在专业上遇到了与您相同的问题),我会在这里添加我的输入。

    REST 服务开发规则严重依赖于 url 定义。以这样一种方式公开您的 api 非常重要,您的客户只需查看 url 定义就可以准确了解每个 api 发生的情况。

    话虽如此,不同的客户(以及不同的工程师)对最佳实践的看法不同。例如,如果您尝试通过电子邮件搜索用户,则至少有两种方法

    1) GET /users/emails/{email} // 客户端可以将其解释为 “通过电子邮件获取用户”

    2) GET /users?email={email} // 客户端可以将其解释为 由于查询参数,“通过电子邮件搜索用户”

    3) GET /users/email={email} // 这可以解释为#1

    这取决于开发人员他们希望如何公开此 api 以及他们如何为客户记录它。从不同的角度来看,所有的方法都是正确的。

    现在具体回答您的问题。这是我的方法在“User”、“Student”和“Teacher”方面的样子。

    我将这 3 个中的每一个都视为单独的资源?为什么?因为它们是单独的类型,即使其中 2 个是从第 3 个扩展而来的。现在我的 apis 会是什么样子?

    对于学生:

    1) 检索学生列表:GET /students

    2) 检索学生 ID:GET /students/{id}

    3) 创建学生:POST /students

    4) 更新学生:PUT /students/{id}

    5) 删除学生:DELETE /students/{id}

    6) 搜索学生:GET /students?{whateverQueryParamsYouWantForSearch}

    同样适用于教师。

    现在是User

    1) GET /users : 检索所有用户的列表 (StudentsTeachers)

    2) GET /users?type={type} :这是踢球者。您可以指定 输入学生或老师,您将返回特定的数据 类型(当然有正确记录)

    3) POST /users?type={type} : 创建特定类型的用户 (studentteacher

    ..等等。

    主要区别是 .. 具有根 url /users 的 api 可用于两种类型的用户(前提是始终指定类型并记录给客户端)。而StudentTeacher api 特定于这些类型。

    我的钱一直花在特定类型上,而通用类型用于搜索(意味着搜索两种类型的用户..使用/users?params)。这是客户了解正在发生的事情的最简单方法。甚至记录它们也容易得多。

    最后谈谈 HATEOAS。是的,这是标准的一部分,最佳做法是始终提供指向您要返回的资源的 url/链接,或者如果您的返回对象很复杂并且包含其他资源,这些资源可能包含本身可能通过 api 公开的资源。例如,

    /users?type=student&email=abc@abc.com
    

    将使用该电子邮件返回所有用户,最好在此处关注 HATEOAS 并向每个返回的用户提供一个 URL,使该 URL 看起来像:/students/{id}。这就是我们通常处理 HATEOAS 的方式

    这就是我要补充的全部内容。正如我之前所说,这是一个非常开放的讨论。每个工程师对标准的解释都不同,没有一种方法可以处理所有用例。有一些基本规则,如果您遵守它们,客户和其他开发人员会为您鼓掌:)

    【讨论】:

    • 对不起,这个答案是完全错误的。 URI 语义与 REST 无关。拥有清晰的 URI 语义可能是一种有效的 HTTP 实践,但是说客户端能够理解 URI 发生的事情非常重要,这完全是荒谬的。这一点都不重要,这就是使用 HATEOAS 的意义所在。
    • 正如我在回复中提到的,每个开发者都有自己的看法。他们都不是对的/错的。从 REST 规范的角度来看,我同意你的看法,但作为一个消耗了大量 REST api 的开发人员,我绝对不同意你的看法。有没有想过像 /abc/{id}/{anohterId}/giveMeCounts 这样的网址?不嘲笑您的评论,但网址对实现很重要,即使规范可能并不严格。
    • 我从来没有说过 URI 对实现不重要。当你说 REST 服务严重依赖于 URI 语义时,我说你错了。这很荒谬,你说这是个人观点,没有主观性。如果客户端交互依赖于 URI 语义,则它与协议耦合,并允许带外信息驱动交互。
    • 您将 HATEOAS 视为无关紧要的次要问题反映了这一点,特别是考虑到它对所提出问题的重要性。如果您没有使用 HATEOAS,那么您就没有使用 REST,如果您使用的是 HATEOAS,那么 URI 的内容对于用户代理来说根本不重要。我相信您已经使用了许多 REST API,但是您应该进一步调查这个问题并了解大多数所谓的“REST”API 根本不是 REST。我保证,你会在这个过程中学到很多东西。
    • 我认为您误解了我的回复,并且可能误解了我在说什么。以下是我对 HATEOAS 所说的话:“最后谈谈 HATEOAS。是的,它是标准的一部分,最佳做法是始终提供指向您要返回的资源的 url/链接,或者如果您的返回对象很复杂并包含其他资源其中可能包含可能通过 api 暴露的资源。”我的回答是针对所提出的问题,而不是针对 HATEOAS。如果您想讨论 HATEOAS,请为此创建另一个线程。
    猜你喜欢
    • 1970-01-01
    • 2011-07-27
    • 2013-12-04
    • 1970-01-01
    • 2016-06-02
    • 2010-11-08
    • 2013-09-18
    • 2017-02-09
    • 1970-01-01
    相关资源
    最近更新 更多