超媒体API:如何正确记录?

时间:2017-01-16 13:54:22

标签: rest api-design hateoas hypermedia

我正在开发我的第一个Hypermedia API。我认为我对事物有很好的把握,但在记录API时,我开始质疑我对整个概念的理解。

问题的核心归结为文档,但可能是我没有正确理解一个或多个方面。如果是这样,请告诉我: - )

记录链接关系

假设我的API中有一个或多或少的通用链接关系(https://example.com/rels/accounts)来链接相关帐户。确切的含义可以在上下文中改变,对吗?

  1. 在我的广告牌(或索引)上,我可能会有一个与该关系相关的链接来浏览所有帐户。
  2. 例如,在另一个资源帐户组上,它可能只链接到属于该组的特定帐户子集。
  3. 我该如何记录这种关系?只是说这是一个帐户集合的链接似乎还不够。然而,这正是RFC5988所做的,只是描述了链接本身的含义。所以这可能是要走的路。

    实际状态转换会使问题变得更糟。我们在此处使用https://example.com/rels/create-account作为示例。如果文档只是说“这是您创建新帐户的位置”,那么它不会对我使用该链接创建资源所做的事情做出任何陈述。文档在哪里说明了一些内容:

      

    您可以将multi multipart / form-data或application / json POST到此端点,该端点至少包含以下字段[...]

    关系本身似乎不是正确的地方。特别是当您考虑到该URL的有效负载也可能在上下文中更改时。在我们的示例中,在帐户组上设置该关系会强制要求省略 accountGroup 字段,因为该值是由上下文提供的。

    记录配置文件

    据我了解,我可以(也可能应该)为我的API中的每个资源创建一个配置文件,记录资源本身。这将包括其属性和可能发生的链接。那会是我指定链接意味着什么的地方吗?

    坚持我之前的示例,我是否会为个人资料https://example.com/profiles/account-group记录关系https://example.com/rels/accounts的链接是否链接到该群组中的一组帐户?

    这对我来说很有意义,但是当我们进入实际状态转换时,事情似乎变得混乱。

    状态转换

    假设客户端从帐户组导航到帐户集合。资源本身与包含所有全局帐户的资源实际上没有区别。它会有分页链接和帐户资源本身的链接。

    如果该帐户收集资源有一个关系类型https://example.com/rel/create-account的链接,我会遇到很大麻烦,对吧?因为这是仅包含特定组帐户的帐户集合的信息未在配置文件中编码 https://example.com/profiles/account-collection,因此不能包含客户在发布到该资源时必须省略 accountGroup 属性的信息。

    具体问题

    1. 我是否正确,关系定义应该是弱的,不包含任何有关我如何与其链接的资源进行交互的信息?
    2. 如果是这样,我可以期望客户端跟踪链接,然后根据该资源的配置文件发现他们可以做什么。这似乎是错误的,特别是对于状态转换。
    3. 如果配置文件应该记录客户端可能对链接资源执行的操作,我无法在API中的多个“跳转”中传输上下文,对吗?
    4. 我应该使用更多的个人资料和关系吗?想到https://example.com/profiles/global-accountshttps://example.com/profiles/account-group-accounts
    5. 我越是想到它,我必须要么错过一个关键部分,要么就是可以通过多种方式解决的问题。因此,我知道这个问题可能没有100%正确答案。但也许有人可以启发我,以便我可以自己做出权衡? :)

2 个答案:

答案 0 :(得分:1)

让我们一次一个点:

<强> 1。基于上下文的链接关系含义

将您的问题重新表述为代码上下文:如何记录&#34; getAccounts()&#34;方法在Billboard和AccountGroup类中意味着什么不同?

显而易见的答案是,您通常不会记录该方法,但是您可以记录这些类,并在其中记录方法。您所指的RFC试图定义某种意义上的通用关系,或者每次都应该意味着相同的关系。您可能会重复使用其中的一些,但您仍需记录该方法及其在课堂中的含义。

类等于您的媒体类型。所以我建议你记录你的媒体类型。

<强> 2。链接和表单,如何定义POST的内容

如果您记录媒体类型,则可以在其中定义您喜欢的内容,包括如何使用其链接。但是,我建议不要定义POST的媒体类型,但要将其设置为Content-Negotiation

客户端知道它必须POST一个帐户,它将使用它认为适合此任务的某些媒体类型。然后,服务器会告诉客户端该格式是否可接受,它还可以提供可接受的媒体类型列表作为回报。

第3。记录配置文件

如果“个人档案”是指媒体类型,那么是的,您应该记录它们。实际上你应该记录媒体类型。

<强> 4。状态转换,基于状态的表示修改

由于帐户组无论如何都是资源,客户端实际上不应该提供它,它应该是&#34; state&#34;新帐户所属的组。

换句话说,客户端获得一个已具有当前帐户组上下文的链接。客户端必须发布一个通用帐户,但服务器知道它应属于当前状态的组(例如,它是URI的一部分)

所以不,客户不应该知道它必须省略一些参数。

<强> 5。问题

  1. 是的,关系不应该定义如何与资源进行交互。媒体类型实际上可以做到这一点(比如定义它的表格必须是POST等),但通常情况下它不是必需的。

  2. 是的,客户不仅会发现可用的转换(链接),还会发现可用的方法。方法(GET,POST,PUT)总是意味着相同的事情,并且它们没有在媒体类型中描述,因为媒体类型只描述表示,而不是资源。服务器通常在响应中提交所有支持的方法,或者明确地响应OPTIONS。

  3. 我仍然不知道你的意思&#34;简介&#34;。如果您的意思是关系配置文件,就像链接定义中的某些数据一样,则为no。上下文/状态在URI中传播。您可以使用URI来&#34;保存&#34;例如,客户端正在一个帐户组内移动。

  4. 不,你不应该为链接关系添加语义。 Media-Type将语义添加到链接。

  5. HTH

答案 1 :(得分:1)

我会尝试比罗伯特的答案更简洁地回答,我认为这会让人感到困惑。

  

假设我的API中有一个或多或少的通用链接关系(https://example.com/rels/accounts)来链接相关帐户。确切的含义可以在上下文中改变,对吗?

否。链接关系的含义是静态的。您的索引(列表列表)页面上的“帐户列表”关系特定于您的应用程序。在您的另一个示例帐户组中,您已经在“集合”资源中,该集合的成员具有链接关系“item”(请参阅​​IANA link relations列表)。

  

实际状态转换会使问题变得更糟。我们在此处使用https://example.com/rels/create-account作为示例。如果文档只是说“这是您创建新帐户的地方”

我会在“帐户列表”页面中添加“创建表单”链接(另一个标准的IANA链接关系)。然后你的客户会去:开始 - &gt; list-of-Xes - &gt;创建形式 - &gt;提交。不存在“create-an-X”或“create-a-Y”链接关系。您可能不允许客户端创建新的集合类型。这使得为​​客户端导航API更长,但减少了他们需要知道的内容(API广度)。

  

[profile]会指定链接的含义吗?

如果您将链接关系设为通用除了描述每个模型类之外的链接关系,则不必在每个模型类的基础上在配置文件中记录这些关系。

  

如果该帐户收集资源有一个关系类型https://example.com/rel/create-account的链接,我会遇到很大的麻烦,对吗?

是的,所以不要这样做!您在那里描述的是将现有资源链接到collection(根据IANA的定义)。我建议您支持客户能够这样做:

LINK http://site/account-collections/some-collection HTTP/1.1
Link: <http://site/accounts/some-account-id>; rel=item
Authorization: Token abc123

这个简单(完整!)的HTTP请求具有将包含现有帐户URI的“item”链接添加到要添加到其中的集合的语义。它不会创建新帐户。 LINK method仍处于草案状态,但自HTTP 1.1(1997)以来一直以某种形式存在。

罗伯特写道:

  

您实际上应记录媒体类型。

我不同意。您也应记录链接关系,但如果可以使用通用链接关系,请尽量不创建它们。