Spring Boot Cheatsheet
REST APIs
Use this Spring Boot reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
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.