HATEOAS 和 API 驱动的表单

2024-06-01

我正在尝试将 HATEOAS 应用于现有应用程序,但在对由 API 响应驱动的表单输入进行建模时遇到问题。

该应用程序允许搜索和预订两个地方之间的连接。第一个端点允许搜索连接GET /connections?from={lat,lon}&to={lat,lon}&departure={dateTime}并返回以下有效负载(响应主体)。

[
  {
    "id": "aaa",
    "carrier": "Fast Bus",
    "price": 3.20,
    "departure": "2019-04-05T12:30"
  },
  {
    "id": "bbb",
    "carrier": "Airport Bus",
    "price": 4.60,
    "departure": "2019-04-05T13:30"
  },
  {
    "id": "ccc",
    "carrier": "Slow bus",
    "price": 1.60,
    "departure": "2019-04-05T11:30"
  }
]

为了对其中一个连接下订单,客户端需要创建一个POST /orders具有以下有效负载之一的请求(请求正文):

  • 需要电子邮件
    {
      "connectionId": "aaa",
      "email": "[email protected] /cdn-cgi/l/email-protection"
    }
    
  • 需要电子邮件和航班号(承运人仅处理 aiprort 连接)
    {
      "connectionId": "bbb",
      "email": "[email protected] /cdn-cgi/l/email-protection",
      "flightNumber": "EA1234"
    }
    
  • 需要电话号码
    {
      "connectionId": "ccc",
      "phoneNumber": "+44 111 222 333"
    }
    

有效负载是不同的,因为不同的连接可能由不同的运营商处理,并且每个连接可能需要提供一些不同的信息集。我想告知API客户端,创建订单时需要哪些字段。我的问题是如何使用 HATEOAS 做到这一点?

我检查了不同的规格,通过阅读规格我可以看出:

  1. HAL http://stateless.co/hal_specification.html & 哈尔形式 https://rwcbook.github.io/hal-forms/#_example_hal_forms_document"_templates"但是,模板本身没有 URI。假设它在自链接上运行,在我的例子中是/连接... not /orders.
  2. JSON-LD https://json-ld.org/learn.html我找不到任何有关表单或模板支持的信息。
  3. JSON-API https://jsonapi.org/我找不到任何有关表单或模板支持的信息。
  4. 集合+JSON http://amundsen.com/media-types/collection/最多有一个"template"每个文档,因此假设集合的所有元素都具有相同的字段,但我的应用程序中并非如此。
  5. Siren https://github.com/kevinswiber/siren看起来像"actions"适合我的用例,但该项目似乎已经死了,并且没有许多主要语言的支持库。
  6. CPHL https://github.com/mikestowe/CPHL该项目似乎已经死了,文档很少,也没有库。
  7. Ion https://ionspec.org/对表单有很好的支持,但我找不到任何支持库。目前看来这只是一个规格。

由 API 驱动的表单这样的常见问题是否仍然无法通过规范和工具解决?


在你的例子中,看起来Connections是资源。目前还不完全清楚是否Orders是真正的资源。我猜可能是的,但是要有一个Order你需要一个Client and Connection。所以,要创建一个Order您将需要公开一个集合,可能来自Client or Connection,可能两者都有。

我认为这种脱节源于“现在我们已经有了可用连接的列表,客户端可以选择一个并创建一个Order这是完全正确的,但它是远程过程调用 (RPC) 思维,而不是 REST。客观上,两者都不比另一个更好,除非在一组特定的项目需求的背景下,并且通常它们不应该混合在一起。

使用 RPC 思维方式,定义创建订单方法(例如使用 OpenAPI),并且任何客户端都应该使用一些带外信息来确定所需的正确形式(即通过阅读 OpenAPI 规范)。

凭借 REST/HATEOAS 心态,正确的方法是公开Orders收集自Connection. Each Connection集合中有一个self链接和一个Order集合(链接或对象,根据应用程序要求定义)。每一项的Order has a self链接,这就是指定可​​供性的地方。一个Order是一种已知类型(即使使用 REST/HATEOAS,客户端和服务也必须至少就共享词汇表达成一致),客户端大概知道如何定义。该词汇表可以使用任何有效的机制来定义——json-ld、XSD 等。

HATEOAS 要求结果包含客户端更新状态所需的所有内容。不能有带外信息(共享词汇表除外)。因此,要解决您的问题,您要么需要公开一组Orders from Connection或者你需要允许Order通过发布到创建Connection。如果后者看起来有点像黑客,那么它可能就是这样。

例如,在 HAL-Forms 中,我会执行以下操作:

{
  "connections": [{
    "id": "aaa",
    "carrier": "Fast Bus",
    "price": 3.20,
    "departure": "2019-04-05T12:30"
    "_links": { 
      "self": { ... }, // link to this connection
      "orders": {} // link to collection of orders for this connection
    }
  },
  , ...],
  "_links": {
    "self": { ... } // link to the collection
  },
  "_templates": { ... } // post/put/patch/delete connection
}

客户将点击链接orders从那里会得到_templates包含管理说明的集合Order资源。这OrderPOST 可能需要连接标识符和客户端信息。这HAL-Forms 规范 https://rwcbook.github.io/hal-forms/定义一个正则表达式属性,可用于指定为任何特定表单元素提供的数据类型。由于您已通过特定连接导航到达订单,因此您可以在您的_templates对于该订单,需要哪些字段。例如/orders?connectionType=aaa将返回一组不同的必需属性/orders?connectionType=bbb但两者都使用相同的self的链接/orders?connectionType={type}并且您可以在 POST/PUT/PATCH 上验证它。

我应该注意到 Spring-HATEOAS 超出了 HAL-Forms 规范并允许多个_links and _templates. See 这个 GitHub 问题 https://github.com/mamund/hal-forms/issues/24.

看起来 HATEOAS/REST 可能比简单的 OpenAPI/RPC API 需要更多的工作,而且确实如此。但是,假设客户设计良好,您将放弃简单性,获得灵活性和弹性。哪种方法是正确的取决于很多因素,其中大多数不是技术因素(团队技能、预期消费者、您对客户的控制程度、维护等)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HATEOAS 和 API 驱动的表单 的相关文章

随机推荐

  • Laravel 验证:存在附加列条件 - 自定义验证规则

    在 Laravel 中指定存在验证规则时 是否有一种方法可以引用另一个字段 我希望能够说输入 a 必须存在于表 a 中 输入 b 必须存在于表 b 中 并且表 b 中列 x 的值必须等于输入 a 最好通过例子来解释 public rules
  • 计算行:如何使用 AG Grid 根据同一列中其他行的值计算特定列的单元格值?

    我想使用同一列中其他行的值对特定行实施自定义计算 我发现AG Grid提供了定义的能力列定义表达式 https www ag grid com javascript data grid cell expressions and aggFun
  • 正则表达式和 ios5 stringByMatching ==> NSRegularExpression

    如何使用等效的 NSRegularExpression 更改此行 NSString encodedPoints apiResponse stringByMatching points capture 1L 谢谢 请记住 您需要 iOS 4
  • workbox webpack 插件从预缓存清单中排除文件夹

    我正在将 workbox webpack 插件与 vue cli 3 一起使用 并且我想将文件夹中的文件排除在外 以免添加到预缓存清单中 请参阅下面我当前的文件结构 src 资产 CSS 壳文件1 svg文件2 svg文件3 svg svg
  • 使用 LINQ 获取两个数组中不同和共同的项目

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 例如 我有
  • 更新 xml 标记的属性

    给定一个 xml 文件作为输入 如何使用新的字符串值修改标签的属性 函数是 updateXMLAttribute Document doc String tag String attribute String newValue impl 我
  • 检查 Option 是否包含特定 Some 值的最佳方法?

    您不能执行以下操作 if option is some option 1 既然如果option is some false第二次比较会出错 做这样的事情的最好方法是什么 我现在正在做什么 if option is some if optio
  • 在界面生成器/故事板中设置 UIButton 图像

    我有一个视图控制器 我在故事板中添加了一个圆形矩形按钮 该应用程序运行良好 我还使用故事板将按钮连接到 segue 我正在尝试为此按钮设置一个自定义图像以用于其开和关状态 我如何访问此按钮并设置其属性 在本例中为开和关图像 这是一个屏幕截图
  • 按组复制数据框

    我有以下数据框 df structure list Group c 1 1 1 1 2 2 2 2 2 2 3 3 3 index c 1 2 3 4 1 2 3 4 5 6 1 2 3 row names c NA 13L class c
  • 当 Eclipse 中打开新编辑器时,如何收到通知?

    我有一个视图希望收到有关所有当前打开的编辑器的通知 我在哪里可以添加监听器来实现此目的 我期望 WorkbenchPage 或 EditorManager 有一些合适的侦听器注册表 但我找不到它 您的视图是否使用org eclipse ui
  • 在 Interface Builder 中调整控件的大小以适合其容器

    假设我有一个分割视图 我想用表视图填充其中的一半 我认为这是一个相当常见的用例 有什么方法可以告诉表视图调整自身大小以适应分割视图 还是我真的必须手动调整它的大小 我已经这样做了 就像乔恩 赫斯首先提到的那样 假设您使用的是 Interfa
  • 使用 python/scapy 迭代 pcap 文件数据包

    我想使用 python scapy 迭代 pcap 文件包 该文件有多个协议 当前迭代是特定于协议的 因此如果下一个数据包来自另一个协议 则迭代会 跳转 我不知道为什么现在会变成这样 我想要一个数据包一个数据包 无论什么协议 小例子 dat
  • Firebase 如何取消订阅

    我在用Ionic2 with Angularfire2访问Firebase Authentication 我访问以下内容rxjs Observable chats ts this firelist this dataService find
  • OnModelCreating 从未被调用

    我开始使用实体框架 问题是我的 OnModelCreating 方法从未被调用 这是我的上下文类 public class TestContext DbContext public TestContext base name TestDBC
  • Python - 从子文件夹进行绝对导入

    基本上我和这个人问同样的问题 如何在Python中进行相对导入 https stackoverflow com questions 72852 how to do relative imports in python 但没有人给他正确的答案
  • 哪些设备支持和不支持 USB 主机模式?

    有人可以提供一份全面的列表 列出哪些设备支持和不支持开箱即用的 USB 主机模式 而无需生根 操作系统重建或电缆黑客攻击 我读到只有平板电脑支持它 然后我读到 Droid 支持它 许多帖子都是几年前发布的 所以不确定 2012 年 3 月的
  • 我如何使用 jQuery 来 ajaxify 表单?

    我正在尝试在不使用 jQuery 插件的情况下 AJAXIFY 表单 实现这一目标的过程是什么 我有我的表格 我应该将操作设置为什么 标题脚本应该是什么 请记住 我不想使用任何插件 我只需要一个使用 jquery ajaxifying 表单
  • “敌人”不是在这个范围内宣布的吗?

    好的 这就是我的错误 Enemy 未在此范围内声明 错误位于 map h 文件中 即使 map h 包含敌人 h 如图所示 ifndef MAP H INCLUDED define MAP H INCLUDED include
  • htaccess - 将所有非 www 流量重定向到 www

    任何人都可以建议我如何使用 htaccess 文件获取非 www 流量重定向到网站的 www 版本 我知道我在根目录中创建了一个网站 但无法确定要放置什么 任何想法 比较容易 匹配任何不以 www 开头的内容 然后重定向到 www 版本 R
  • HATEOAS 和 API 驱动的表单

    我正在尝试将 HATEOAS 应用于现有应用程序 但在对由 API 响应驱动的表单输入进行建模时遇到问题 该应用程序允许搜索和预订两个地方之间的连接 第一个端点允许搜索连接GET connections from lat lon to la