Spring Boot Cheatsheet
REST APIs
Use this Spring Boot reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
REST Design Conventions in Spring Boot
| HTTP Method | Annotation | Typical Path | Status Returned |
|---|---|---|---|
| GET (list) | @GetMapping | /api/users | 200 |
| GET (single) | @GetMapping("/{id}") | /api/users/42 | 200 / 404 |
| POST (create) | @PostMapping | /api/users | 201 + Location |
| PUT (full update) | @PutMapping("/{id}") | /api/users/42 | 200 |
| PATCH (partial) | @PatchMapping("/{id}") | /api/users/42 | 200 |
| DELETE | @DeleteMapping("/{id}") | /api/users/42 | 204 |
Minimal REST Controller
@RestController @RequestMapping("/api/v1/articles") @RequiredArgsConstructor public class ArticleController { private final ArticleService service; @GetMapping public ResponseEntity<List<ArticleDto>> list( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { return ResponseEntity.ok(service.list(page, size)); } @GetMapping("/{id}") public ResponseEntity<ArticleDto> get(@PathVariable Long id) { return ResponseEntity.ok(service.getById(id)); } @PostMapping @ResponseStatus(HttpStatus.CREATED) public ArticleDto create(@Valid @RequestBody CreateArticleRequest req) { return service.create(req); } @PutMapping("/{id}") public ArticleDto update(@PathVariable Long id, @Valid @RequestBody UpdateArticleRequest req) { return service.update(id, req); } @DeleteMapping("/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) public void delete(@PathVariable Long id) { service.delete(id); } }
DTOs and Records
Prefer Java records (immutable) for request/response DTOs:
// Request DTO public record CreateArticleRequest( @NotBlank String title, @NotBlank @Size(max = 5000) String body, @NotNull Long authorId ) {} // Response DTO public record ArticleDto( Long id, String title, String body, String authorName, Instant createdAt ) {}
Mapping with MapStruct
@Mapper(componentModel = "spring") public interface ArticleMapper { ArticleDto toDto(Article article); Article toEntity(CreateArticleRequest req); void updateEntity(@MappingTarget Article entity, UpdateArticleRequest req); }
Pagination and Sorting
// Spring Data Page — add spring-boot-starter-data-jpa @GetMapping public Page<ArticleDto> list(Pageable pageable) { // GET /api/articles?page=0&size=10&sort=createdAt,desc return service.list(pageable); }
// In service / repository Page<Article> articles = repository.findAll(pageable); return articles.map(mapper::toDto);
Add
@EnableSpringDataWebSupporton a@Configurationclass (or rely on Spring Boot autoconfiguration) to resolvePageablefrom request params automatically.
Content Negotiation
@GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) public ArticleDto get(@PathVariable Long id) { ... }
Add jackson-dataformat-xml dependency for XML support:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>Jackson Customization
// On DTO fields @JsonProperty("full_name") // rename in JSON @JsonIgnore // exclude from output @JsonInclude(NON_NULL) // omit null fields @JsonFormat(pattern="yyyy-MM-dd") // date format @JsonSerialize(using = MySerializer.class)
// Global config via application.properties spring.jackson.default-property-inclusion=non_null spring.jackson.serialization.write-dates-as-timestamps=false spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss
// Or via @Bean @Bean public Jackson2ObjectMapperBuilderCustomizer customizer() { return builder -> builder .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .modules(new JavaTimeModule()) .serializationInclusion(JsonInclude.Include.NON_NULL); }
Standard Error Response Body
public record ApiError( int status, String error, String message, Instant timestamp, String path ) {}
@ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ApiError> handleNotFound(ResourceNotFoundException ex, HttpServletRequest request) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body( new ApiError(404, "Not Found", ex.getMessage(), Instant.now(), request.getRequestURI()) ); }
CORS Configuration
// Per-controller or per-method @CrossOrigin(origins = "https://myapp.com", maxAge = 3600) // Global — in a @Configuration class @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(List.of("https://myapp.com")); config.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS")); config.setAllowedHeaders(List.of("*")); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/api/**", config); return source; }
Versioning Strategies
// URI versioning (most common) @RequestMapping("/api/v1/users") // Header versioning @GetMapping(headers = "X-API-Version=2") // Accept header (media type) versioning @GetMapping(produces = "application/vnd.myapp.v2+json")
Hypermedia (HATEOAS)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; @GetMapping("/{id}") public EntityModel<ArticleDto> get(@PathVariable Long id) { ArticleDto dto = service.getById(id); return EntityModel.of(dto, linkTo(methodOn(ArticleController.class).get(id)).withSelfRel(), linkTo(methodOn(ArticleController.class).list(0, 10)).withRel("articles") ); }
Actuator Endpoints
management.endpoints.web.exposure.include=health,info,metrics,loggers management.endpoint.health.show-details=when-authorized
| Endpoint | Path |
|---|---|
| Health | GET /actuator/health |
| Info | GET /actuator/info |
| Metrics | GET /actuator/metrics/{name} |
| Loggers | GET/POST /actuator/loggers/{name} |
| Env | GET /actuator/env |
| Beans | GET /actuator/beans |
Common Gotchas
@ResponseStatuson exception class vs. handler method — both work, but@ControllerAdvicehandlers take precedence.Pageablenot resolving — ensurespring-boot-starter-data-webor@EnableSpringDataWebSupportis active.HttpMessageNotWritableException— usually a missing no-arg constructor on a DTO, or a circular reference in a JPA entity.- Empty
PageJSON vs. list —Page<T>serializes with metadata (content,totalElements, etc.); if you want a plain array, map toList<T>first. - Enabling CORS and Security — call
http.cors(withDefaults())in yourSecurityFilterChainso theCorsConfigurationSourcebean is actually used.