Marketplace

spring-rest-api

Build production-ready REST APIs with Spring MVC - controllers, validation, exception handling, OpenAPI

$ 설치

git clone https://github.com/pluginagentmarketplace/custom-plugin-spring-boot /tmp/custom-plugin-spring-boot && cp -r /tmp/custom-plugin-spring-boot/skills/spring-rest-api ~/.claude/skills/custom-plugin-spring-boot

// tip: Run this command in your terminal to install the skill


name: spring-rest-api description: Build production-ready REST APIs with Spring MVC - controllers, validation, exception handling, OpenAPI sasmp_version: "1.3.0" bonded_agent: 02-spring-mvc bond_type: PRIMARY_BOND version: "2.0.0" updated: "2024-12-30"

Spring REST API Skill

Master building robust, well-documented REST APIs with Spring MVC including validation, error handling, and OpenAPI documentation.

Overview

This skill covers everything needed to build production-grade REST APIs following industry best practices.

Parameters

NameTypeRequiredDefaultValidation
api_versionstringv1Pattern: v[0-9]+
content_typeenumjsonjson | xml | both
documentationenumopenapiopenapi | none

Topics Covered

Core (Must Know)

  • REST Controllers: @RestController, @RequestMapping
  • Request Handling: Path variables, query params, request body
  • Response Building: ResponseEntity, status codes
  • Bean Validation: @Valid, @NotNull, custom validators

Intermediate

  • Exception Handling: @ControllerAdvice, Problem Details (RFC 7807)
  • Content Negotiation: JSON/XML, custom converters
  • CORS Configuration: Cross-origin resource sharing

Advanced

  • HATEOAS: Hypermedia-driven APIs
  • API Versioning: URL, header strategies
  • OpenAPI Documentation: springdoc-openapi

Code Examples

Complete REST Controller

@RestController
@RequestMapping("/api/v1/products")
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;

    @GetMapping
    public Page<ProductResponse> list(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        return productService.findAll(PageRequest.of(page, size));
    }

    @GetMapping("/{id}")
    public ProductResponse get(@PathVariable Long id) {
        return productService.findById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public ProductResponse create(@Valid @RequestBody CreateProductRequest request) {
        return productService.create(request);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Long id) {
        productService.delete(id);
    }
}

Request DTO with Validation

public record CreateProductRequest(
    @NotBlank(message = "Name is required")
    @Size(min = 2, max = 100)
    String name,

    @NotNull @DecimalMin("0.01")
    BigDecimal price,

    @Size(max = 1000)
    String description
) {}

Global Exception Handler

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ProblemDetail handleNotFound(ResourceNotFoundException ex) {
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(
            HttpStatus.NOT_FOUND, ex.getMessage());
        problem.setTitle("Resource Not Found");
        problem.setProperty("timestamp", Instant.now());
        return problem;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ProblemDetail handleValidation(MethodArgumentNotValidException ex) {
        ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
        problem.setTitle("Validation Failed");
        Map<String, String> errors = ex.getBindingResult()
            .getFieldErrors().stream()
            .collect(Collectors.toMap(
                FieldError::getField,
                e -> e.getDefaultMessage() != null ? e.getDefaultMessage() : "Invalid"
            ));
        problem.setProperty("errors", errors);
        return problem;
    }
}

Troubleshooting

Failure Modes

IssueDiagnosisFix
404 on valid pathMissing @RestControllerAdd annotation
Request body nullMissing @RequestBodyAdd to parameter
Validation ignoredMissing @ValidAdd before @RequestBody

Debug Checklist

□ Verify @RestController on class
□ Check @RequestMapping path
□ Confirm @Valid on request body
□ Test with curl to isolate issues
□ Check Content-Type header

Unit Test Template

@WebMvcTest(ProductController.class)
class ProductControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private ProductService productService;

    @Test
    void shouldCreateProduct() throws Exception {
        mockMvc.perform(post("/api/v1/products")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\":\"Test\",\"price\":19.99}"))
            .andExpect(status().isCreated());
    }
}

Usage

Skill("spring-rest-api")

Version History

VersionDateChanges
2.0.02024-12-30RFC 7807, OpenAPI, comprehensive examples
1.0.02024-01-01Initial release