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 MethodAnnotationTypical PathStatus Returned
GET (list)@GetMapping/api/users200
GET (single)@GetMapping("/{id}")/api/users/42200 / 404
POST (create)@PostMapping/api/users201 + Location
PUT (full update)@PutMapping("/{id}")/api/users/42200
PATCH (partial)@PatchMapping("/{id}")/api/users/42200
DELETE@DeleteMapping("/{id}")/api/users/42204

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 @EnableSpringDataWebSupport on a @Configuration class (or rely on Spring Boot autoconfiguration) to resolve Pageable from 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
EndpointPath
HealthGET /actuator/health
InfoGET /actuator/info
MetricsGET /actuator/metrics/{name}
LoggersGET/POST /actuator/loggers/{name}
EnvGET /actuator/env
BeansGET /actuator/beans

Common Gotchas

  • @ResponseStatus on exception class vs. handler method — both work, but @ControllerAdvice handlers take precedence.
  • Pageable not resolving — ensure spring-boot-starter-data-web or @EnableSpringDataWebSupport is active.
  • HttpMessageNotWritableException — usually a missing no-arg constructor on a DTO, or a circular reference in a JPA entity.
  • Empty Page JSON vs. listPage<T> serializes with metadata (content, totalElements, etc.); if you want a plain array, map to List<T> first.
  • Enabling CORS and Security — call http.cors(withDefaults()) in your SecurityFilterChain so the CorsConfigurationSource bean is actually used.