【发布时间】:2021-09-27 12:51:59
【问题描述】:
我最近阅读了 Spring.io 官方教程网站上关于在 Spring Boot 中实现 RESTful API 的指南(教程链接:https://spring.io/guides/tutorials/rest/)
但是,指南中的某些内容似乎与我对如何构建 REST API 的理解相矛盾。我现在想知道是我的理解有误,还是该指南的质量没有我预期的那么高。
我的问题是这个 PUT 方法的实现来更新订单状态:
@PutMapping("/orders/{id}/complete")
ResponseEntity<?> complete(@PathVariable Long id) {
Order order = orderRepository.findById(id) //
.orElseThrow(() -> new OrderNotFoundException(id));
if (order.getStatus() == Status.IN_PROGRESS) {
order.setStatus(Status.COMPLETED);
return ResponseEntity.ok(assembler.toModel(orderRepository.save(order)));
}
return ResponseEntity //
.status(HttpStatus.METHOD_NOT_ALLOWED) //
.header(HttpHeaders.CONTENT_TYPE, MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE) //
.body(Problem.create() //
.withTitle("Method not allowed") //
.withDetail("You can't complete an order that is in the " + order.getStatus() + " status"));
}
从我在https://restfulapi.net/rest-put-vs-post/ 阅读的内容来看,PUT 方法应该是幂等的;这意味着您应该能够连续多次调用它而不会引起问题。但是,在此实现中,只有第一个 PUT 请求会产生影响,并且对同一资源的所有进一步 PUT 请求都会导致错误消息。
根据 RESTful API 可以吗?如果没有,什么是更好的使用方法?我不认为 POST 会更好。
此外,在同一指南中,他们以类似的方式使用 DELETE 方法将订单状态更改为取消:
@DeleteMapping("/orders/{id}/cancel")
ResponseEntity<?> cancel(@PathVariable Long id) {
Order order = orderRepository.findById(id) //
.orElseThrow(() -> new OrderNotFoundException(id));
if (order.getStatus() == Status.IN_PROGRESS) {
order.setStatus(Status.CANCELLED);
return ResponseEntity.ok(assembler.toModel(orderRepository.save(order)));
}
return ResponseEntity //
.status(HttpStatus.METHOD_NOT_ALLOWED) //
.header(HttpHeaders.CONTENT_TYPE, MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE) //
.body(Problem.create() //
.withTitle("Method not allowed") //
.withDetail("You can't cancel an order that is in the " + order.getStatus() + " status"));
}
这对我来说看起来很不对劲。我们这里没有删除任何东西,它与前面的 PUT 方法基本相同,只是我们想要移动到不同的状态。我认为本教程的这一部分是伪造的是否正确?
TL;DR:当您想将资源的状态推进到下一阶段而不提供返回到较早阶段的选项时,使用哪种 HTTP 方法是正确的?基本上是一个更新/补丁,它会使自己的先决条件无效。
【问题讨论】:
-
技术上它是幂等的。无论您PUT多少次/完成它只会完成一次,当订单状态为Status.IN_PROGRESS时。当您尝试完成已完成的订单时,所有其他调用将导致 HttpStatus.METHOD_NOT_ALLOWED。删除也一样。您只能删除一次。幂等性在服务器端。
标签: rest put restful-url