我们目前正在处理来自我们巨石的小型服务。我们的域名与票务系统非常相似。我们已决定从域名的取消流程开始。
我们的取消服务具有简单的端点“取消”,它接收票证的ID。在内部,我们检索id,执行与取消相关的一些操作,并更新商店中实体的状态。从商店的角度来看,取消的机票和实时机票之间的唯一区别是一些属性。
根据我的阅读,PATCH似乎是在这种情况下使用的正确动词,因为我只更新资源中的一个简单属性。
PATCH /api/tickets/{id}
Payload {isCancelled: true}
但isCancelled不是实体中的实际属性。在有效载荷中发送不属于实体的属性是否公平,还是应该考虑对此请求建模的其他形式?我不希望将整个实体作为有效载荷的一部分发送,因为它很大。
我考虑过创建一个新的资源CancelledTickets,但在我们的域名中,我们永远不需要在取消的门票上获得GET。因此,不必创建新资源。
答案 0 :(得分:5)
看看究竟是什么RESTful way。无论您是以PATCH
作为有效负载发送isCancelled
请求,还是DELETE
,如果您希望机票消失。它仍然是RESTful。
您的举动取决于您的需求。如你所说
我考虑过创建一个新的资源CancelledTickets,但在我们的 域名我们永远不需要在取消的门票上获得GET。
我只想发送DELETE
。您不必将其物理移除。如果可以取消取消,则实施isCancelled
机制。这只是品味的问题。
答案 1 :(得分:3)
公开资源的GET
接口不是强制性的。
例如,使用
PUT /api/tickets/{id}/actions/cancel
提交取消请求。我选择PUT
,因为生效的取消请求不会超过一个。
希望它有所帮助。
答案 2 :(得分:2)
REST基本上是基于浏览器的Web的概括。您应用于Web的任何概念也可以应用于REST。
那么,您如何设计网页中的取消活动?您可能会有一个表格行,其中包含某些活动,例如带有图标和鼠标悬停文本的概述的编辑和删除,单击这些文件将在服务器上调用URI并导致跟踪状态。您不太感兴趣该按钮的URI的外观,或者是否在背面调用了PATCH或DELETE命令。您只是对请求的处理感兴趣。
如果您想通过REST执行相同的操作,则同样适用。代替暗示用户对条目执行编辑或取消活动的图像,应该使用有意义的链接关系名称来暗示客户端有关可能性。您的情况可能类似于reserve new tickets
,edit reservation
或cancel reservation
。每个链接关系名称都附带一个URL,如果客户要执行一项活动,则可以调用该URL。 URI的确切字符在这里对客户端也不重要。可能已经在响应中提供了要调用的方法(作为其他随附字段),也可能通过响应所针对的媒体类型来提供。如果媒体类型和随附字段均未提示使用OPTIONS请求的HTTP操作可能事先在URI上发出。经验法则是,服务器应教客户如何最终实现目标。
通过遵循这样的概念,您可以使客户端与API脱钩,并使它对更改具有鲁棒性。代替客户端生成用于调用客户端的URI,服务器向服务器提供可能调用的URI。如果服务器更改了其内部URI结构,则使用提供的URI之一的客户端仍将能够调用该服务,因为它仅使用了服务器提供的URI之一。通过分析提示客户端何时调用此类URI的链接关系名称来确定使用哪个。如上所述,此类链接关系名称需要在某处定义。但这正是Fielding在2008年提出的主张:
REST API应该花费几乎所有的描述性精力来定义用于表示资源和驱动应用程序状态的媒体类型,或者为现有标准媒体定义扩展关系名称和/或启用超文本的标记类型。 (Source)
选择哪种HTTP操作来取消票证/预订可能取决于您的意愿。尽管建议DELETE
RFC 7231给出的某些答案指出,仅删除了URI和资源之间的关联,但也没有保证也将实际的资源也删除了。如果您设计的系统中取消操作可能被撤消,那么DELETE
并不是您的正确选择,因为在处理DELETE
请求之后,URI与资源的映射应该不再存在。但是,如果您认为取消也导致取消预订,则可以使用DELETE
。
如果您以一种将状态保持为资源内属性的方式对资源进行建模,则PATCH
使用资源可能是有效的选择。但是,仅发送state=canceled
之类的信息在这里可能还不够,因为PATCH
是对客户为了将某种资源(或多种资源)转换成所需目标状态而执行的步骤的计算。 JSON Patch可能会提供有关如何完成此操作的线索。还需要对PATCH
具有的原子性要求进行进一步说明。所有指令要么成功,要么根本不成功。
在其他答案之一中也提到了PUT
。 PUT
的语义是用请求的有效负载中给定的URI替换给定URI上的当前表示。进一步允许服务器拒绝内容或将其转换为更合适的表示形式,并且还影响其他资源,即它们是否模仿资源的版本历史记录。
如果上述操作均不能真正满足您的需求,则应使用POST
,因为这是HTTP的万能的swiss-army-knife工具包。尽管此操作通常用于创建新资源,但不限于此。它应在其他操作的语义不适用的任何情况下使用。根据{{3}}
POST方法要求目标资源根据资源自身的特定语义来处理请求中包含的表示形式。
这基本上是免费出狱卡。在这里,您可以根据自己的规则从字面上处理服务器上的任何内容。如果您想取消或暂停某件事,只需执行该操作即可。
我强烈不建议使用GET
创建,更改或取消/删除某些内容。 GET
是一种安全的操作,可以确保任何调用客户端的客户端都不会更改服务器上被调用资源的任何状态。请注意,尽管实际状态不受调用的影响,但它可能会有较小的副作用,即日志记录。这是Web搜寻器依赖的属性。他们将仅通过GET
调用任何URI,并了解接收到的响应的内容。而且我认为您不希望Google(或任何其他爬网程序)取消所有预订,还是吗?
如上所述,应使用哪种HTTP操作取决于您的设计。 DELETE
仅在您也将要删除表示形式的情况下使用,尽管规范不一定要求这样做,但是一旦映射到资源的URI消失了,您基本上就无法进一步调用该资源(当然,除非您先创建了另一个URI映射)。如果您设计资源以将状态保持在某个属性内,那么我可能会选择PATCH
,但总的来说,这里我基本上会选择POST
,因为这里您将拥有所有选择。 / p>
答案 3 :(得分:0)
以静态方式为CANCEL Action建模: 假设我们必须通过提供noteId(便笺的ID)来删除数据库中的便笺,并且便笺是pojo
1]在控制器上:
@DeleteMapping(value="/delete/{noteId}")
public ResponseEntity<Note> deleteNote( @PathVariable Long noteId)
{
noteServiceImpl.deleteNote(noteId);
return ResponseEntity.ok().build();
}
2]服务层:
@Service
public class NoteServiceImpl {
@Autowired
private NotesRepository notesDao;
public void deleteNote(Long id) {
notesDao.delete(id);
}
}
3]存储库层:
@Repository
public interface NotesRepository extends CrudRepository<Note, Long> {
}
和4分邮递员:http://localhost:8080/delete/1
因此,我们已通过CANCEL Action从数据库中删除了注释ID 1
答案 4 :(得分:0)
我建议拥有一个国家资源。
这使事情保持 RESTful。您将 HTTP 方法用作动词。 URI 的状态部分是一个名词。那么您的请求正文就简单且与 URI 一致。
对此我唯一不喜欢的是 state 的值需要文档,这意味着有哪些 state?这可以通过 API 解决,方法是在元资源或元对象中的票体的一部分上提供可能的状态。
PUT /api/tickets/:id/state
{state: "canceled"}
GET /api/meta/tickets/state
// returns
[
"canceled",
...
]
GET /api/tickets/:id
{
id: ...
meta: {
states: [
"canceled",
...
]
}
}