← 返回首页

RESTful API设计详解

📂 java ⏱ 3 min 485 words

什么是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最佳实践

  1. 使用名词表示资源
  2. 使用HTTP方法表示操作
  3. 使用合适的HTTP状态码
  4. 支持分页和过滤
  5. 提供API文档

总结

RESTful API设计是现代Web服务的标准。遵循REST原则能帮助你设计清晰、可维护的API接口。