【问题标题】:REST API for data processing and method chaining用于数据处理和方法链接的 REST API
【发布时间】:2015-10-14 04:01:20
【问题描述】:

如果问题质量不好,我提前道歉。我还在开始学习 REST API 的概念。我正在尝试为数据处理实现可扩展的 REST API。到目前为止,这是我能想到的。

考虑一些可以使用GET 调用检索的数字数据:

GET http://my.api/data/123/

用户可以应用一系列算术运算,例如addmultiply。一种非 RESTful 方式是:

GET http://my.api/data/123?add=10&multiply=5

假设:

  • 数据库中的原始数据没有改变。只会将修改后的版本返回给用户。
  • 数据很大(比如一个大的多维数组),所以我们不能在每次操作调用时都返回整个数据。相反,我们希望将操作作为批处理应用并最终返回最终修改后的数据。

我目前正在考虑两种 RESTful 方式:

1。将算术运算建模为数据的子资源。

如果我们将addmultiply 视为数据as here 的子资源。在这种情况下,我们可以使用:

GET http://my.api/data/123/add/10/

这将是安全和幂等的,因为原始数据永远不会改变。但是,我们需要链接多个操作。我们可以这样做吗?

GET http://my.api/data/123/add/10/multiply/5/

multiply 正在创建add/10/ 的子资源,而data/123 本身就是data/123 的子资源

优点:

  • 无状态:服务器不保留有关修改数据的任何信息。
  • 轻松访问修改后的数据:这只是一个简单的 GET 调用。

缺点:

  • Chaining:不知道能不能轻松实现。
  • 长 URI:每次应用操作后,URI 都会变得越来越长。

2。创建一个可编辑数据对象:

在这种情况下,用户创建原始数据的可编辑版本:

POST http://my.api/data/123/

将返回

201 Created
Location: http://my.api/data/123/edit/{uniqueid}

然后用户可以PATCH这个可编辑的数据

PATCH http://my.api/data/123/edit/{uniqueid}
{add:10, multiply:5}

最后,GET 编辑的数据

GET http://my.api/data/123/edit/{uniqueid}

优点:

  • 清理 URI。

缺点:

  • 服务器必须保存已编辑数据的状态。
  • 编辑不再是幂等的。
  • 获取已编辑的数据需要用户至少拨打 3 次电话。

是否有一种更简洁、更语义化的方式来以 REST 方式实现数据处理?

编辑:

如果您想知道这背后的现实问题是什么,我正在处理数字信号处理。

作为一个简单的示例,您可以考虑将视觉过滤器应用于图像。在this example 之后,一个 RESTful Web 服务可以做到:

GET http://my.api/image/123/blur/5px/rotate/90deg/?size=small&format=png

【问题讨论】:

  • 为什么“GET my.api/data/123?add=10&multiply=5”不是RESTful?这假设没有状态
  • 嗯,这取决于你如何解释它。我看到 addmultiply 修改了资源,而不是 scoop 它。我认为查询字符串应该保留用于例如GET http://my.api/data/123/add/10/?subset_from=0&subset_to=10 中的挖掘。
  • @ahmohamed,这是一个真正的问题吗?
  • @Opal 当然。我的应用程序涉及信号处理。我已经编辑了这个问题来证明这一点。
  • 为什么不想/不能保留修改后的数据?

标签: web-services rest restful-architecture


【解决方案1】:

您的问题中有几件事值得回顾。

基于 REST 的 API 是基于资源的

所以看看你的第一个例子,尝试将转换属性链接到资源标识符之后的 URL 路径中......

GET http://my.api/data/123/add/10/multiply/5/

.. 不太合适(正如你已经猜到的那样,动态实现也很复杂)

无国籍状态

REST 中的无状态概念是围绕单个 HTTP 调用构建的,该调用包含足够的信息来处理请求并提供结果,而无需返回客户端获取更多信息。在服务器上存储 HTTP 调用的结果不是状态,而是缓存。


现在,鉴于基于 REST 的 API 可能不是最适合您的使用,如果您仍想使用它,这里有您的选择:

1.将查询字符串与常见的 URL 操作一起使用

您可以使用查询字符串,但简化资源路径以接受单个 URI 上的所有转换。鉴于您的示例和不愿存储转换结果,这可能是您的最佳选择。

GET http://my.api/data/123/transform?add=10&multiply=5

2。以非 RESTful 方式使用 POST

您可以使用 POST 请求,并利用 HTTP 正文发送转换参数。如果您决定进行 lot 处理,这将确保您永远不会用完查询字符串的空间,并且还可以使您的通信更加整洁。如果 POST 返回图像数据,则这不被视为 RESTful。

3。 RESTful 使用 POST

最后,如果您决定确实要缓存内容,您的 POST 实际上可以存储转换后的对象(请注意,REST 并未规定如何将其存储在内存或 DB 等中),这可以重新通过 Id 使用 GET 获取。

选项 A

POST 到 URI 会创建一个从属资源。

POST http://my.api/data/123
{add:10, multiply:5}

返回

201 Created
Location: http://my.api/data/123/edit/{uniqueid}

然后获取编辑后的数据

GET http://my.api/data/123/edit/{uniqueid}

选项 B

从 URL 中删除资源标识符,以表明您正在创建一个新项目,而不是更改现有项目。生成的 URL 也与原始 URL 处于同一级别,因为它假定它是相同类型的结果。

POST http://my.api/data
{original: 123, add:10, multiply:5}

返回

201 Created
Location: http://my.api/data/{uniqueid}

然后获取编辑后的数据

GET http://my.api/data/{uniqueid}

【讨论】:

  • 非常感谢您的回答。我目前倾向于 RESTful POST 选项 A http://my.api/data/123/edit/{uniqueid},因为它在指示响应是数据的编辑副本方面更具语义。数据可以在短期缓存中存储到服务器以实现可扩展性
  • 由于这个问题的目的是引发对该主题的讨论,我会接受你的回答,因为你讨论了几个选项。
【解决方案2】:

有多种方法可以做到这一点。最后它应该是干净的,不管你想给它什么标签(REST非REST)。 REST 不是一个带有 RFC 的协议,所以不要太担心你是否将信息作为 URL 路径或 URL 参数传递。无论数据如何传递,底层 Web 服务都应该能够为您获取数据。例如,Java Jersey 会为您提供参数,无论它们是参数还是 URL 路径,它只是一个注释差异。

回到您的具体问题,我认为此 REST 类型调用中的资源与其说是用于执行数字运算的数据,不如说是实际响应。在这种情况下,数据 ID 和操作是字段的 POST 可能就足够了。

POST http://my.api/operations/

{
    "dataId": "123",
    "operations": [
        {
            "type": "add",
            "value": 10
        },
        {
            "type": "multiply",
            "value": 5
        }
    ]
}

正如您所指出的,响应必须指向可以检索结果的位置。由响应中的位置(和 ID)引用的结果本质上是一个不可变对象。所以这实际上是 POST 创建的资源,而不是用于计算该结果的数据。它只是一种不同的查看方式。

编辑:针对您关于不想存储操作结果的评论,您可以使用回调将操作结果传输给调用者。您可以轻松地在 JSON 输入中为回调的主机或 URL 添加 a 字段。如果存在回调 URL,那么您可以将操作结果发布到该 URL。

{
    "dataId": "123",
    "operations": [
        {
            "type": "add",
            "value": 10
        },
        {
            "type": "multiply",
            "value": 5
        }
    ],
    "callBack": "<HOST or URL>"
}

【讨论】:

  • 这绝对是我要走的路。这样你就可以POST http://my.api/image/123/filters {"blur":"5px", "rotate":"90deg", "size":"small", "format":"png"},拥有你需要的一切。
  • 非常感谢您的回答。你的绝对是一种方法(而且我相信这个问题没有一个正确的答案)。但我认为这种方式也无法扩展,因为它每次都会创建多个数据副本。
  • 是否打算更改数据?我认为该操作的目的是不改变原始数据,而客户端只想要操作的输出。
  • 我觉得你的理解是对的。原始数据资源没有改变。我的意思是“创建副本”是指每个请求都会创建一个新资源(具有更改的数据)。由于数据大小(以及因此更改的数据)很大,这带来了可扩展性问题。
  • 3 点需要考虑。首先,无论您使用 POST、GET、JSON 还是 params,这都不应该影响底层实现。如果实现创建了需要保留的额外对象,则更改它。第二点是您的要求The data is large in size (say a large multi-dimensional array), so we can't afford to return the whole data with every opertation call. Instead, we want to apply operations as a batch and return the final modified data in the end.。第三点,如果你不想在计算完对象后存储它,那么你可以使用回调。
【解决方案3】:

请不要将此视为我在回答我自己的问题,而是对讨论的贡献。

我对此进行了很多思考。当前建议的架构的主要问题是可扩展性,因为服务器每次操作时都会创建数据副本。

避免这种情况的唯一方法是分别对operationsdata 建模。因此,类似于 Jose 的回答,我们创建了一个资源:

POST http://my.api/operations/
{add:10, multiply:5}

请注意,我根本没有指定数据。创建的资源仅代表一系列操作。 POST 返回:

201 Created
Location: http://my.api/operations/{uniqueid}

下一步是在数据上应用operations

GET http://my.api/data/123/operations/{uniqueid}

这种单独的建模方法有几个优点:

  1. 不会在每次应用不同的操作集时复制数据。
  2. 用户只创建operations 资源,由于它们的大小很小,我们不必担心可扩展性。
  3. 用户创建新资源仅在他们需要组操作时。转到图像示例:如果我正在设计一个灰度网站,并且我想要所有图片要转灰度,我可以做

    POST http://my.api/operations/
    {greyscale: "50%"}
    

    然后应用这个操作在我所有的图片上:

    GET http://my.api/image/{image_id}/operations/{geyscale_id}
    

    只要我不想改变操作集,我只能使用GET

  4. 可以在服务器上创建和存储常用操作,因此用户不必创建它们。例如:

    GET http://my.api/image/{image_id}/operations/flip
    

    其中operations/flip 已经是一个可用的操作集。

  5. 很容易,将同一组操作应用于不同的数据,反之亦然。

    GET http://my.api/data/{id1},{id2}/operations/{some_operation}
    

    使您能够比较两个处理方式相似的数据集。或者:

    GET http://my.api/data/{id1}/operations/{some_operation},{another_operation}
    

    让您了解不同的处理程序如何影响结果。

【讨论】:

    【解决方案4】:

    我不会尝试使用 URI 或请求正文来描述您的数学函数。我们有或多或少的标准语言来描述数学,因此您可以使用某种模板。

    GET http://my.api/data/123?transform="5*(data+10)"
    POST http://my.api/data/123 {"transform": "5*({data}+10)"}
    

    你需要一个在客户端的代码,它可以构建这些模板和另一个在服务器端的代码,它可以验证,解析等......客户端构建的模板。

    【讨论】:

    • 这里的数学运算只是数据处理的一个例子。我认为我们没有像您描述的那样处理信号(或图像)的标准语言。
    猜你喜欢
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 2018-07-20
    • 1970-01-01
    • 2019-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多