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 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.