超媒体API:如何正确撰写文档?

3
我正在开发我的第一个超媒体API。 我认为我对这个有很好的掌握,但是在文档编写方面,我开始质疑自己对整个概念的理解。
问题的核心在于文档,但可能是我没有正确理解一个或多个方面。 如果是这样,请告诉我 :-)
记录链接关系
假设我在我的API中有一个更加通用的链接关系(https://example.com/rels/accounts),用于链接相关帐户。 具体含义可以根据上下文而变化,对吗?
在我的宣传牌上(或索引)上,我可能会使用该关系的链接来浏览所有帐户。
例如,在另一个资源-帐户组上,它可能仅链接到属于该组的特定子集。
我应该如何记录该关系?仅说明这是一个帐户收藏的链接似乎不够。然而,这正是{{link1:RFC5988}}所做的,只是描述链接本身的含义。因此,这可能是可行的方法。
问题在实际状态转换中会变得更加严重。让我们以https://example.com/rels/create-account作为例子。如果文档只是说“这是您创建新帐户的位置”,它并没有说明我必须如何使用该链接来创建资源。是否有类似以下内容的文档:

您可以将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 是我想到的。

越想越觉得,我必须要么缺少关键部分,要么可以用多种方式解决。因此,我知道可能没有100%正确的答案。但也许有人能启迪我,让我可以做出自己的权衡? :)

2个回答

1
让我们逐一解决你的问题:
1. 基于上下文的链接关系含义
将你的问题转化为代码上下文:当“getAccounts()”在 Billboard 类和 AccountGroup 类中的含义不同时,如何记录该方法?
显然的答案是不要总体记录该方法,而是记录类及其中的方法。你所引用的 RFC 尝试定义某种意义上通用的关系,或者应该每次都有相同的含义。你可以重复使用其中一些,但仍需记录该方法及其在类中的含义。
类等同于你的媒体类型。因此,我建议你记录你的媒体类型。
2. 链接和表单,如何定义 POST 内容
如果你记录了你的媒体类型,你可以在其中定义任何你喜欢的内容,包括如何使用其链接。然而,我建议不要定义 POST 的媒体类型,而是让它由内容协商来决定。
客户端知道它必须POST一个账户,它将使用一些媒体类型来完成这个任务。然后,服务器会告诉客户端是否可接受该格式,还可以返回可接受的媒体类型列表。
3. 如果您所说的Profile是指媒体类型,那么是的,您应该记录它们。您实际上应该只记录媒体类型。
4. 状态转换、基于状态的表示修改
由于账户组本身就是资源,因此客户端实际上不应该提供它,它应该是新账户所属的“状态”的一部分。
换句话说,客户端获得了一个链接,它已经具有当前账户组的上下文。客户端必须发布一个通用账户,但服务器知道它应该属于当前状态中的组(例如,它是URI的一部分)。
所以不,客户端不应该知道它必须省略某些参数。
5. 问题
  1. 是的,关系不应该定义如何与资源交互。媒体类型可以做到这一点(例如表单定义必须是POST等),但往往没有必要。

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

  3. 我仍然不太清楚你所说的“Profile”的含义。如果你指的是关系配置文件,就像链接定义中的某些数据,那么不行。上下文/状态在URI中传递。您可以使用URI来“保存”客户端正在移动到一个帐户组内部。

  4. 不,您不应该向链接关系添加语义。媒体类型为链接添加了语义。

希望对您有所帮助。


一个"Profile(配置文件)"定义了现有媒体类型的额外约束条件。application/hal+json; profile=https://example.com/profile/customer 表示文档符合 hal+json 媒体类型,同时还受到给定配置文件的限制。简而言之,您实际上并不是定义新的媒体类型,而是使用自己的规则增强它们。我认为这是一个相当不错的概念。更多信息请参见:https://tools.ietf.org/html/draft-kelly-json-hal-08#section-7.1 https://tools.ietf.org/html/rfc6906 - Malax
关于第二点:无论其编码方式如何,我仍然需要记录端点期望的业务特定数据。这在“PATCH”请求中变得更加棘手,因为它们绝对需要一些文档说明。这是否应该成为文档化媒体类型的一部分?例如:application/vnd.acme.customer 期望您将 X、Y 发布到 https://example.com/rels/edit 链接,但不包括 Z? - Malax
谢谢提供有关Profiles的链接,对我来说,它看起来像是媒体类型的某种“子类”。我需要再考虑一下。关于2:该链接定义了您可以导航的位置。这应该是GET。当您在资源上时,编辑始终是PUT。但是通常,链接不应定义可能跟随的媒体类型。这是内容协商的一部分,也是GET请求的一部分。这有意义吗? - Robert Bräutigam
我赞同内容协商的观点,但永远使用GET来链接似乎让我感到困惑。我会使用链接来指示可以对资源的当前状态执行哪些操作,例如delete。我为什么要通过GET跟随链接呢?或者删除当前资源的事实是否仅由对当前资源(或Allow标头)的OPTIONS请求处理?但是,我仍然对所需资源本身(而不是其表示)的文档有问题。我没有“关键词”,可以将该文档附加到其中。 - Malax
让我们在聊天中继续这个讨论 - Malax
显示剩余3条评论

1

我会比罗伯特的回答更简洁地回答,我觉得他的回答可能会让人感到困惑。

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

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

实际状态转换的问题变得更加严重。让我们以https://example.com/rels/create-account为例。如果文档只是说“这是您创建新帐户的位置”

我建议在“账户列表”页面上添加一个“创建表单”链接(另一个标准的IANA链接关系)。你的客户将会依次进行以下步骤:开始 -> X列表 -> 创建表单 -> 提交。不需要使用“创建X”或“创建Y”链接关系。你可能也不允许客户创建新的集合类型。这使得客户在API导航时更加繁琐,但减少了他们需要了解的内容(API广度)。

我的个人资料里是否可以指定链接的确切含义?

如果你的链接关系是通用的,除了描述每个模型类的一个之外,那么你就不必按每个模型类的基础来在个人资料中记录它们。

如果该帐户集合资源具有关系类型为https://example.com/rel/create-account 的链接,那我会陷入麻烦,对吗?

是的,所以不要这样做!你所描述的是将现有资源链接到一个集合(根据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方法 仍处于草案阶段,但自HTTP 1.1(1997年)以来已经存在某种形式。
Robert写道:
“实际上,你应该记录媒体类型。”
我不同意。您也应该记录链接关系,但如果可以使用通用链接关系,则尽量不创建它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接