REST API 用于数据处理和方法链接
REST API for data processing and method chaining
如果问题质量不好,我提前道歉。我还在开始学习 REST 的概念 API。我正在尝试为数据处理实现可扩展的 REST API。到目前为止,这是我能想到的。
考虑一些可以使用 GET
调用检索的数值数据:
GET http://my.api/data/123/
用户可以应用一系列算术运算,例如add
和multiply
。一种非 RESTful 的方法是:
GET http://my.api/data/123?add=10&multiply=5
假设:
- 数据库中的原始数据没有改变。只有修改后的版本才会 return 提供给用户。
- 数据量很大(比如说一个大的多维数组),所以我们无法 return 每次操作调用都处理整个数据。相反,我们希望将操作作为批处理应用,并 return 最后修改的数据。
我目前考虑的方法有 2 RESTful 种:
1。将算术运算建模为数据的子资源。
如果我们将 add
和 multiply
视为数据 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
的子资源
优点:
- 无状态:服务器不保留有关修改数据的任何信息。
- 轻松访问修改后的数据:这只是一个简单的 GET 调用。
缺点:
- 链式:不知道是否容易实现。
- 长 URI:随着每个操作的应用,URI 变得越来越长。
2。创建一个 可编辑 数据对象:
在这种情况下,用户创建了原始数据的可编辑版本:
POST http://my.api/data/123/
将return
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 次电话。
是否有更简洁、更语义化的方式来实现数据处理 RESTfully?
编辑:
如果您想知道这背后的现实世界问题是什么,我正在处理数字信号处理。
作为一个简单的例子,您可以考虑对图像应用视觉滤镜。在 this example 之后,一个 RESTful 网络服务可以做:
GET http://my.api/image/123/blur/5px/rotate/90deg/?size=small&format=png
您的问题中有几点值得回顾。
基于 REST API 是基于资源的
所以看看你的第一个例子,试图将转换属性链接到资源标识符后面的 URL 路径中..
GET http://my.api/data/123/add/10/multiply/5/
..不太合适(正如您已经猜到的那样,动态实施起来也很复杂)
无国籍
REST 中的无状态思想是围绕单个 HTTP 调用构建的,该调用包含足够的信息来处理请求并提供结果,而无需返回客户端以获取更多信息。在服务器上存储 HTTP 调用的结果不是状态,而是缓存。
现在,考虑到基于 REST 的 API 可能不是最适合您的用途,如果您仍然想使用它,这里有您的选择:
1。使用具有常见 URL 操作的 Querystring
您可以使用 Querystring 但简化资源路径以接受基于单个 URI 的所有转换。鉴于您的示例和不愿意存储转换后的结果,这可能是您的最佳选择。
GET http://my.api/data/123/transform?add=10&multiply=5
2。使用POST非RESTfully
您可以使用 POST 请求,并利用 HTTP 正文发送转换参数。如果您决定进行 lot 处理,这将确保您永远不会 运行 超出查询字符串的 space 并且它还会保留你的沟通更整洁。如果 POST returns 图像数据,则不考虑 RESTful。
3。使用 POST RESTfully
最后,如果您决定要缓存内容,您的 POST 实际上可以存储转换后的对象(请注意,REST 不规定这是如何存储的,在内存或数据库等中。 ) 可以使用 GET 由 Id 重新获取。
选项A
POSTing to the URI creates a subordinate resource.
POST http://my.api/data/123
{add:10, multiply:5}
returns
201 Created
Location: http://my.api/data/123/edit/{uniqueid}
然后获取修改后的数据
GET http://my.api/data/123/edit/{uniqueid}
选项 B
Remove the resource identifier from the URL to make it clear that you're creating a new item, not changing the existing one. The resulting URL is also at the same level as the original one since it's assumed it's the same type of result.
POST http://my.api/data
{original: 123, add:10, multiply:5}
returns
201 Created
Location: http://my.api/data/{uniqueid}
然后获取修改后的数据
GET http://my.api/data/{uniqueid}
有多种方法可以做到这一点。最后它应该是干净的,不管你想给它什么标签(REST 非 REST)。 REST 不是带有 RFC 的协议,所以不要太担心将信息作为 URL 路径还是 URL 参数传递。不管数据是如何传递的,底层网络服务都应该能够为您提供数据。例如 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,那么您可以 POST 使用操作结果 URL。
{
"dataId": "123",
"operations": [
{
"type": "add",
"value": 10
},
{
"type": "multiply",
"value": 5
}
],
"callBack": "<HOST or URL>"
}
我不会尝试使用 URI 或请求正文来描述您的数学函数。我们有或多或少的标准语言来描述数学,因此您可以使用某种模板。
GET http://my.api/data/123?transform="5*(data+10)"
POST http://my.api/data/123 {"transform": "5*({data}+10)"}
您需要一个客户端代码,它可以构建这些类型的模板和另一个服务器端代码,它可以验证、解析等...客户端构建的模板。
请不要将此视为我在回答自己的问题,而是对讨论的贡献。
我对此进行了很多思考。当前建议的体系结构的主要问题是可伸缩性,因为服务器在每次操作时都会创建数据副本。
避免这种情况的唯一方法是分别对 operations
和 data
建模。因此,类似于 Jose 的回答,我们创建了一个资源:
POST http://my.api/operations/
{add:10, multiply:5}
注意这里,我根本没有指定数据。创建的资源仅代表一系列操作。 POST
returns:
201 Created
Location: http://my.api/operations/{uniqueid}
下一步是应用数据上的operations
:
GET http://my.api/data/123/operations/{uniqueid}
这种单独的建模方法有几个优点:
- 数据不会在每次应用不同的操作集时都被复制。
- 用户只创建
operations
资源,由于它们的大小很小,我们不必担心可伸缩性。
用户 创建 一个新资源,只有当他们需要 new 组 operations.Going 到图片示例:如果我正在设计一个灰度网站,并且我希望所有图像都转换为灰度,我可以这样做
POST http://my.api/operations/
{greyscale: "50%"}
然后对我的所有图像应用此操作:
GET http://my.api/image/{image_id}/operations/{geyscale_id}
只要不想改变操作集就可以只用GET
常用的操作可以创建并存储在服务器上,用户无需创建。例如:
GET http://my.api/image/{image_id}/operations/flip
其中operations/flip
已经是可用的操作集
很容易,将同一组操作应用于不同的数据,反之亦然。
GET http://my.api/data/{id1},{id2}/operations/{some_operation}
使您能够比较两个处理相似的数据集。或者:
GET http://my.api/data/{id1}/operations/{some_operation},{another_operation}
允许您查看不同的处理过程如何影响结果。
如果问题质量不好,我提前道歉。我还在开始学习 REST 的概念 API。我正在尝试为数据处理实现可扩展的 REST API。到目前为止,这是我能想到的。
考虑一些可以使用 GET
调用检索的数值数据:
GET http://my.api/data/123/
用户可以应用一系列算术运算,例如add
和multiply
。一种非 RESTful 的方法是:
GET http://my.api/data/123?add=10&multiply=5
假设:
- 数据库中的原始数据没有改变。只有修改后的版本才会 return 提供给用户。
- 数据量很大(比如说一个大的多维数组),所以我们无法 return 每次操作调用都处理整个数据。相反,我们希望将操作作为批处理应用,并 return 最后修改的数据。
我目前考虑的方法有 2 RESTful 种:
1。将算术运算建模为数据的子资源。
如果我们将 add
和 multiply
视为数据 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
优点:
- 无状态:服务器不保留有关修改数据的任何信息。
- 轻松访问修改后的数据:这只是一个简单的 GET 调用。
缺点:
- 链式:不知道是否容易实现。
- 长 URI:随着每个操作的应用,URI 变得越来越长。
2。创建一个 可编辑 数据对象:
在这种情况下,用户创建了原始数据的可编辑版本:
POST http://my.api/data/123/
将return
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 次电话。
是否有更简洁、更语义化的方式来实现数据处理 RESTfully?
编辑:
如果您想知道这背后的现实世界问题是什么,我正在处理数字信号处理。
作为一个简单的例子,您可以考虑对图像应用视觉滤镜。在 this example 之后,一个 RESTful 网络服务可以做:
GET http://my.api/image/123/blur/5px/rotate/90deg/?size=small&format=png
您的问题中有几点值得回顾。
基于 REST API 是基于资源的
所以看看你的第一个例子,试图将转换属性链接到资源标识符后面的 URL 路径中..
GET http://my.api/data/123/add/10/multiply/5/
..不太合适(正如您已经猜到的那样,动态实施起来也很复杂)
无国籍
REST 中的无状态思想是围绕单个 HTTP 调用构建的,该调用包含足够的信息来处理请求并提供结果,而无需返回客户端以获取更多信息。在服务器上存储 HTTP 调用的结果不是状态,而是缓存。
现在,考虑到基于 REST 的 API 可能不是最适合您的用途,如果您仍然想使用它,这里有您的选择:
1。使用具有常见 URL 操作的 Querystring
您可以使用 Querystring 但简化资源路径以接受基于单个 URI 的所有转换。鉴于您的示例和不愿意存储转换后的结果,这可能是您的最佳选择。
GET http://my.api/data/123/transform?add=10&multiply=5
2。使用POST非RESTfully
您可以使用 POST 请求,并利用 HTTP 正文发送转换参数。如果您决定进行 lot 处理,这将确保您永远不会 运行 超出查询字符串的 space 并且它还会保留你的沟通更整洁。如果 POST returns 图像数据,则不考虑 RESTful。
3。使用 POST RESTfully
最后,如果您决定要缓存内容,您的 POST 实际上可以存储转换后的对象(请注意,REST 不规定这是如何存储的,在内存或数据库等中。 ) 可以使用 GET 由 Id 重新获取。
选项A
POSTing to the URI creates a subordinate resource.
POST http://my.api/data/123
{add:10, multiply:5}
returns
201 Created
Location: http://my.api/data/123/edit/{uniqueid}
然后获取修改后的数据
GET http://my.api/data/123/edit/{uniqueid}
选项 B
Remove the resource identifier from the URL to make it clear that you're creating a new item, not changing the existing one. The resulting URL is also at the same level as the original one since it's assumed it's the same type of result.
POST http://my.api/data
{original: 123, add:10, multiply:5}
returns
201 Created
Location: http://my.api/data/{uniqueid}
然后获取修改后的数据
GET http://my.api/data/{uniqueid}
有多种方法可以做到这一点。最后它应该是干净的,不管你想给它什么标签(REST 非 REST)。 REST 不是带有 RFC 的协议,所以不要太担心将信息作为 URL 路径还是 URL 参数传递。不管数据是如何传递的,底层网络服务都应该能够为您提供数据。例如 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,那么您可以 POST 使用操作结果 URL。
{
"dataId": "123",
"operations": [
{
"type": "add",
"value": 10
},
{
"type": "multiply",
"value": 5
}
],
"callBack": "<HOST or URL>"
}
我不会尝试使用 URI 或请求正文来描述您的数学函数。我们有或多或少的标准语言来描述数学,因此您可以使用某种模板。
GET http://my.api/data/123?transform="5*(data+10)"
POST http://my.api/data/123 {"transform": "5*({data}+10)"}
您需要一个客户端代码,它可以构建这些类型的模板和另一个服务器端代码,它可以验证、解析等...客户端构建的模板。
请不要将此视为我在回答自己的问题,而是对讨论的贡献。
我对此进行了很多思考。当前建议的体系结构的主要问题是可伸缩性,因为服务器在每次操作时都会创建数据副本。
避免这种情况的唯一方法是分别对 operations
和 data
建模。因此,类似于 Jose 的回答,我们创建了一个资源:
POST http://my.api/operations/
{add:10, multiply:5}
注意这里,我根本没有指定数据。创建的资源仅代表一系列操作。 POST
returns:
201 Created
Location: http://my.api/operations/{uniqueid}
下一步是应用数据上的operations
:
GET http://my.api/data/123/operations/{uniqueid}
这种单独的建模方法有几个优点:
- 数据不会在每次应用不同的操作集时都被复制。
- 用户只创建
operations
资源,由于它们的大小很小,我们不必担心可伸缩性。 用户 创建 一个新资源,只有当他们需要 new 组 operations.Going 到图片示例:如果我正在设计一个灰度网站,并且我希望所有图像都转换为灰度,我可以这样做
POST http://my.api/operations/ {greyscale: "50%"}
然后对我的所有图像应用此操作:
GET http://my.api/image/{image_id}/operations/{geyscale_id}
只要不想改变操作集就可以只用
GET
常用的操作可以创建并存储在服务器上,用户无需创建。例如:
GET http://my.api/image/{image_id}/operations/flip
其中
operations/flip
已经是可用的操作集很容易,将同一组操作应用于不同的数据,反之亦然。
GET http://my.api/data/{id1},{id2}/operations/{some_operation}
使您能够比较两个处理相似的数据集。或者:
GET http://my.api/data/{id1}/operations/{some_operation},{another_operation}
允许您查看不同的处理过程如何影响结果。