RESTful API 和现实生活中的例子
RESTful API and real life example
我们有一个 Web 应用程序(AngularJS 和 Web API),它具有非常简单的功能 - 显示作业列表并允许用户 select 和取消 select编辑工作。
我们正尝试通过我们的 API 遵循 RESTful 方法,但这正是令人困惑的地方。
找工作很容易 - 简单 GET: /jobs
我们如何取消 selected 的工作?请记住,这是我们需要实施的唯一作业操作。最简单和最合乎逻辑的方法(对我来说)是将 selected 作业 ID 列表发送到 API(服务器)并执行必要的程序。但这不是 RESTful 方式。
如果我们按照 RESTful 方法进行操作,我们需要将 PATCH 请求发送到 jobs
,json 类似于:
PATCH: /jobs
[
{
"op": "replace",
"path": "/jobs/123",
"status": "cancelled"
},
{
"op": "replace",
"path": "/jobs/321",
"status": "cancelled"
},
]
这将需要在客户端生成此 json,然后将其映射到服务器上的某些模型,解析 "path"
属性 以获取作业 ID,然后进行实际取消。这对我来说似乎非常复杂和人为。
对这种操作的一般建议是什么?我很好奇当很多操作不能简单地映射到 RESTful 资源范例时,人们在现实生活中会做什么。
谢谢!
如果取消一个工作你的意思是删除它那么你可以使用DELETE
动词:
DELETE /jobs?ids=123,321,...
如果取消工作你的意思是将一些status字段设置为cancelled那么你可以使用 PATCH
动词:
PATCH /jobs
Content-Type: application/json
[ { "id": 123, "status": "cancelled" }, { "id": 321, "status": "cancelled" } ]
PUT /jobs{/ids}/status "cancelled"
例如
PUT /jobs/123,321/status "cancelled"
如果您想取消多个作业。请注意,作业 ID 不得包含逗号字符。
POST 业务流程
在这种情况下,POST
通常是一个被忽视的解决方案。将资源视为名词是 REST 中一种有用且常见的做法,因此,POST 通常从 CRUD 语义映射到“CREATE”操作 - 然而 HTTP Spec for POST 没有强制要求这样的事情:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
- Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
- Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
- Creating a new resource that has yet to be identified by the origin server; and
- Appending data to a resource's existing representation(s).
在你的情况下,你可以使用:
POST /jobs/123/cancel
并将其视为第一个选项的示例 - 向数据处理过程提供数据块 - 类似于使用 POST 提交表单的 html 表单。
使用此技术,您可以 return 正文中的作业表示 and/or return 一个 303 See Other
状态代码,其 Location 设置为 /jobs/123
有些人抱怨这看起来 'too RPC' - 但如果你阅读规范,没有什么不是 RESTful - 我个人觉得它比试图找到一个任意的更清楚从 CRUD 操作到实际业务流程的映射。
理想情况下,如果您关心遵循 REST 规范,取消操作的 URI 应该通过作业表示中的超媒体 link 提供给客户端。例如如果您使用的是 HAL,您将拥有:
GET /jobs/123
{
"id": 123,
"name": "some job name",
"_links" : {
"cancel" : {
"href" : "/jobs/123/cancel"
},
"self" : {
"href" : "/jobs/123"
}
}
}
客户端然后可以获取“取消”rel link 的 href 和 POST 以实现取消。
将进程视为资源
另一种选择是,根据它在您的域中是否有意义,使 'cancellation' 成为名词并将数据与之相关联,例如谁取消了它,何时取消等等 - 这是如果一个作业可能被取消、重新打开和再次取消,因为更改历史可能是有用的业务数据,或者如果取消操作是一个异步过程,需要随时间跟踪取消请求的状态,则特别有用。通过这种方法,您可以使用:
POST /jobs/123/cancellations
这将“创建”作业取消 - 然后您可以进行如下操作:
GET /jobs/123/cancellations/1
到return与取消相关的数据,例如
{
"cancelledBy": "Joe Smith",
"requestedAt": "2016-09-01T12:43:22Z",
"status": "in process"
"completedAt": null
}
和:
GET /jobs/123/cancellations
到 return 已应用到作业的取消集合及其当前状态。
示例 1:让我们将其与现实世界的示例进行比较:您去一家餐厅,坐在 table 前,您选择需要 ABC。您将让您的服务员过来并记下您想要的东西。你告诉他你想要 ABC。所以,你要求 ABC,服务员用 ABC 回应他进入厨房并为你提供食物。在这种情况下,您和厨房之间的接口是谁是您的服务员。他有责任将您的请求带到厨房,确保完成,您知道一旦准备就绪,他就会回复您。
示例 2:我们可以关联的另一个重要示例是旅行预订系统。例如,以最大的在线订票网站 Kayak 为例。你输入你的目的地,一旦你 select 日期并点击搜索,你得到的是来自不同航空公司的结果。 Kayak 如何与所有这些航空公司沟通?这些航空公司实际上通过某些方式向 Kayak 公开了某种程度的信息。说了这么多,都是通过API的
示例 3:现在打开 UBER 看看。网站加载后,您就可以登录或继续使用 Facebook 和 Google。在这种情况下,Google 和 Facebook 也暴露了一定程度的用户信息。 UBER 和 Google/Facebook 之间已经达成协议。这就是它允许您注册 Google/ Facebook 的原因。
我们有一个 Web 应用程序(AngularJS 和 Web API),它具有非常简单的功能 - 显示作业列表并允许用户 select 和取消 select编辑工作。
我们正尝试通过我们的 API 遵循 RESTful 方法,但这正是令人困惑的地方。
找工作很容易 - 简单 GET: /jobs
我们如何取消 selected 的工作?请记住,这是我们需要实施的唯一作业操作。最简单和最合乎逻辑的方法(对我来说)是将 selected 作业 ID 列表发送到 API(服务器)并执行必要的程序。但这不是 RESTful 方式。
如果我们按照 RESTful 方法进行操作,我们需要将 PATCH 请求发送到 jobs
,json 类似于:
PATCH: /jobs
[
{
"op": "replace",
"path": "/jobs/123",
"status": "cancelled"
},
{
"op": "replace",
"path": "/jobs/321",
"status": "cancelled"
},
]
这将需要在客户端生成此 json,然后将其映射到服务器上的某些模型,解析 "path"
属性 以获取作业 ID,然后进行实际取消。这对我来说似乎非常复杂和人为。
对这种操作的一般建议是什么?我很好奇当很多操作不能简单地映射到 RESTful 资源范例时,人们在现实生活中会做什么。
谢谢!
如果取消一个工作你的意思是删除它那么你可以使用DELETE
动词:
DELETE /jobs?ids=123,321,...
如果取消工作你的意思是将一些status字段设置为cancelled那么你可以使用 PATCH
动词:
PATCH /jobs
Content-Type: application/json
[ { "id": 123, "status": "cancelled" }, { "id": 321, "status": "cancelled" } ]
PUT /jobs{/ids}/status "cancelled"
例如
PUT /jobs/123,321/status "cancelled"
如果您想取消多个作业。请注意,作业 ID 不得包含逗号字符。
POST 业务流程
在这种情况下,POST
通常是一个被忽视的解决方案。将资源视为名词是 REST 中一种有用且常见的做法,因此,POST 通常从 CRUD 语义映射到“CREATE”操作 - 然而 HTTP Spec for POST 没有强制要求这样的事情:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
- Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
- Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
- Creating a new resource that has yet to be identified by the origin server; and
- Appending data to a resource's existing representation(s).
在你的情况下,你可以使用:
POST /jobs/123/cancel
并将其视为第一个选项的示例 - 向数据处理过程提供数据块 - 类似于使用 POST 提交表单的 html 表单。
使用此技术,您可以 return 正文中的作业表示 and/or return 一个 303 See Other
状态代码,其 Location 设置为 /jobs/123
有些人抱怨这看起来 'too RPC' - 但如果你阅读规范,没有什么不是 RESTful - 我个人觉得它比试图找到一个任意的更清楚从 CRUD 操作到实际业务流程的映射。
理想情况下,如果您关心遵循 REST 规范,取消操作的 URI 应该通过作业表示中的超媒体 link 提供给客户端。例如如果您使用的是 HAL,您将拥有:
GET /jobs/123
{
"id": 123,
"name": "some job name",
"_links" : {
"cancel" : {
"href" : "/jobs/123/cancel"
},
"self" : {
"href" : "/jobs/123"
}
}
}
客户端然后可以获取“取消”rel link 的 href 和 POST 以实现取消。
将进程视为资源
另一种选择是,根据它在您的域中是否有意义,使 'cancellation' 成为名词并将数据与之相关联,例如谁取消了它,何时取消等等 - 这是如果一个作业可能被取消、重新打开和再次取消,因为更改历史可能是有用的业务数据,或者如果取消操作是一个异步过程,需要随时间跟踪取消请求的状态,则特别有用。通过这种方法,您可以使用:
POST /jobs/123/cancellations
这将“创建”作业取消 - 然后您可以进行如下操作:
GET /jobs/123/cancellations/1
到return与取消相关的数据,例如
{
"cancelledBy": "Joe Smith",
"requestedAt": "2016-09-01T12:43:22Z",
"status": "in process"
"completedAt": null
}
和:
GET /jobs/123/cancellations
到 return 已应用到作业的取消集合及其当前状态。
示例 1:让我们将其与现实世界的示例进行比较:您去一家餐厅,坐在 table 前,您选择需要 ABC。您将让您的服务员过来并记下您想要的东西。你告诉他你想要 ABC。所以,你要求 ABC,服务员用 ABC 回应他进入厨房并为你提供食物。在这种情况下,您和厨房之间的接口是谁是您的服务员。他有责任将您的请求带到厨房,确保完成,您知道一旦准备就绪,他就会回复您。
示例 2:我们可以关联的另一个重要示例是旅行预订系统。例如,以最大的在线订票网站 Kayak 为例。你输入你的目的地,一旦你 select 日期并点击搜索,你得到的是来自不同航空公司的结果。 Kayak 如何与所有这些航空公司沟通?这些航空公司实际上通过某些方式向 Kayak 公开了某种程度的信息。说了这么多,都是通过API的
示例 3:现在打开 UBER 看看。网站加载后,您就可以登录或继续使用 Facebook 和 Google。在这种情况下,Google 和 Facebook 也暴露了一定程度的用户信息。 UBER 和 Google/Facebook 之间已经达成协议。这就是它允许您注册 Google/ Facebook 的原因。