RESTful API设计详解
什么是REST
REST(Representational State Transfer)是一种软件架构风格,通过HTTP协议进行资源的CRUD操作。
RESTful API设计原则
资源命名
@RestController
@RequestMapping("/api/v1")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping("/products")
public List<Product> getAllProducts() {
return productService.findAll();
}
@GetMapping("/products/{id}")
public Product getProduct(@PathVariable Long id) {
return productService.findById(id);
}
@PostMapping("/products")
public Product createProduct(@RequestBody Product product) {
return productService.save(product);
}
@PutMapping("/products/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
return productService.update(id, product);
}
@DeleteMapping("/products/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
productService.delete(id);
return ResponseEntity.noContent().build();
}
}
查询参数
@RestController
@RequestMapping("/api/products")
public class ProductQueryController {
@GetMapping
public Page<Product> searchProducts(
@RequestParam(required = false) String name,
@RequestParam(required = false) BigDecimal minPrice,
@RequestParam(required = false) BigDecimal maxPrice,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return productService.search(name, minPrice, maxPrice, PageRequest.of(page, size));
}
}
嵌套资源
@RestController
@RequestMapping("/api/users/{userId}/orders")
public class UserOrderController {
@GetMapping
public List<Order> getUserOrders(@PathVariable Long userId) {
return orderService.findByUserId(userId);
}
@PostMapping
public Order createOrder(@PathVariable Long userId, @RequestBody Order order) {
order.setUserId(userId);
return orderService.save(order);
}
}
HTTP状态码
@RestController
@RequestMapping("/api/products")
public class ProductApiController {
@PostMapping
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
Product created = productService.save(product);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(
@PathVariable Long id, @RequestBody Product product) {
Product updated = productService.update(id, product);
return ResponseEntity.ok(updated);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
productService.delete(id);
return ResponseEntity.noContent().build();
}
@GetMapping("/{id}")
public ResponseEntity<Product> getProduct(@PathVariable Long id) {
return productService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}
API版本控制
@RestController
@RequestMapping("/api/v1/products")
public class ProductV1Controller {
@GetMapping
public List<ProductV1> getAllProducts() {
return productService.findAllV1();
}
}
@RestController
@RequestMapping("/api/v2/products")
public class ProductV2Controller {
@GetMapping
public List<ProductV2> getAllProducts() {
return productService.findAllV2();
}
}
统一响应格式
public class ApiResponse<T> {
private int code;
private String message;
private T data;
private long timestamp;
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(200);
response.setMessage("success");
response.setData(data);
response.setTimestamp(System.currentTimeMillis());
return response;
}
public static <T> ApiResponse<T> error(int code, String message) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(code);
response.setMessage(message);
response.setTimestamp(System.currentTimeMillis());
return response;
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiResponse<Void>> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.error(404, ex.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Void>> handleGeneral(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponse.error(500, "Internal Server Error"));
}
}
HATEOAS
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/products")
public class ProductHateoasController {
@GetMapping("/{id}")
public EntityModel<Product> getProduct(@PathVariable Long id) {
Product product = productService.findById(id);
EntityModel<Product> resource = EntityModel.of(product);
resource.add(WebMvcLinkBuilder.linkTo(
WebMvcLinkBuilder.methodOn(this.getClass()).getProduct(id)).withSelfRel());
resource.add(WebMvcLinkBuilder.linkTo(
WebMvcLinkBuilder.methodOn(this.getClass()).getAllProducts()).withRel("products"));
return resource;
}
}
CORS配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
API文档
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/products")
@Tag(name = "产品管理", description = "产品的CRUD操作")
public class ProductSwaggerController {
@Operation(summary = "获取产品列表", description = "分页获取所有产品")
@GetMapping
public List<Product> getAllProducts() {
return productService.findAll();
}
@Operation(summary = "创建产品")
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productService.save(product);
}
}
RESTful最佳实践
- 使用名词表示资源
- 使用HTTP方法表示操作
- 使用合适的HTTP状态码
- 支持分页和过滤
- 提供API文档
总结
RESTful API设计是现代Web服务的标准。遵循REST原则能帮助你设计清晰、可维护的API接口。