Every request that enters your API needs validation. Without it, invalid data propagates through your application and produces confusing errors deep in the stack. This article covers how to validate data at the API boundary using Jakarta Bean Validation. Setup <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> This includes Hibernate Validator — the reference implementation of Jakarta Bean Validation 3.0. Built-in Constraints Annotate fields in your DTO with constraint annotations: public record CreateOrderRequest( @NotNull(message = "Customer ID is required") UUID customerId, @NotEmpty(message = "Order must contain at least one item") @Size(max = 50, message = "Order cannot have more than {max} items") List<@Valid OrderItemRequest> items, @Valid ShippingAddressRequest shippingAddress, @Size(max = 20, message = "Promo code cannot exceed {max} characters") String promoCode ) {} public record OrderItemRequest( @NotNull UUID productId, @Positive(message = "Quantity must be positive") @Max(value = 999, message = "Cannot order more than {value} units of a product") int quantity, @NotNull @Positive BigDecimal unitPrice ) {} public record ShippingAddressRequest( @NotBlank(message = "Address line 1 is required") @Size(max = 100) String line1, @Size(max = 100) String line2, @NotBlank @Size(max = 50) String city, @NotBlank @Pattern(regexp = "[A-Z]{2}", message = "Country must be a 2-letter ISO code") String country, @NotBlank @Pattern(regexp = "\\w{3,10}", message = "Invalid postal code format") String postalCode ) {} Common Constraint Annotations Annotation Validates @NotNull Value is not null @NotEmpty String/collection not null and not empty @NotBlank String not null, not empty, not just whitespace @Size(min, max) String length or collection size @Min(value) Number ≥ value @Max(value) Number ≤ value @Positive Number > 0 @PositiveOrZero Number ≥ 0 @Negative Number < 0 @Pattern(regexp) String matches regex @Email Valid email format @Past Date is in the past @Future Date is in the future @DecimalMin(value) Decimal ≥ value (as string) @AssertTrue Boolean is true @AssertFalse Boolean is false Triggering Validation with @Valid Add @Valid to the controller parameter to trigger validation:
Continue reading »Tutorial
264 posts in this section
Best Practices Reference: The Complete Liquibase Checklist
Twenty-three articles of Liquibase knowledge, distilled into one reference. Bookmark this page. Use the checklists before every production deployment. Come back when something breaks. This article doesn’t repeat the “why” — that’s in the earlier articles. This is the what: concrete rules, with the article number if you need the full explanation. The 7 Laws (Non-Negotiable) These apply without exception. Break them and you will eventually have a bad day in production.
Continue reading »Building a Modular Monolith with Spring Modulith
Microservices solve organizational and scalability problems — but they add operational complexity. Most applications don’t need that complexity. A modular monolith gives you clean boundaries and loose coupling without the distributed systems overhead. Spring Modulith enforces those boundaries. The Problem with Unstructured Monoliths Without explicit boundaries, every part of the codebase can talk to every other part: // OrderService calling PaymentRepository directly — skipping the Payment module @Service public class OrderService { @Autowired PaymentRepository paymentRepository; // ← wrong @Autowired NotificationService notificationService; // ← wrong @Autowired AnalyticsService analyticsService; // ← wrong } This creates hidden coupling.
Continue reading »Building Your First REST API with Spring Boot
Time to build something real. In this article you’ll create a fully functional REST API for the order-service — create, read, update, and delete orders over HTTP. Project Setup Start with these dependencies at start.spring.io: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> spring-boot-starter-web includes: Embedded Tomcat (no WAR deployment needed) Spring MVC (the web framework) Jackson (JSON serialization) The Request Processing Pipeline Before writing code, understand how Spring MVC handles a request:
Continue reading »Caching with Caffeine and Redis
Caching sits between your application and the database. A cache hit returns data in microseconds; a database query takes milliseconds. For frequently-read, infrequently-changed data, caching is the highest-leverage performance improvement. Spring Cache Abstraction Spring’s cache abstraction lets you add caching with annotations — the backing store (Caffeine, Redis, Hazelcast) is swappable: @Service @RequiredArgsConstructor public class ProductService { private final ProductRepository repository; @Cacheable("products") // cache the result public Product findById(UUID id) { return repository.
Continue reading »Centralized Configuration with Spring Cloud Config Server
Managing configuration for 10 services across 3 environments means 30 separate config files. Spring Cloud Config Server centralizes all of them — one place to change a database URL, one place to rotate secrets, and services pick up changes without redeployment. Config Server Setup <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> @SpringBootApplication @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } } # application.yml — config-server server: port: 8888 spring: application: name: config-server cloud: config: server: git: uri: https://github.
Continue reading »Changelog Formats: XML, YAML, JSON, and SQL — When to Use Each
Liquibase supports four changelog formats: XML, YAML, JSON, and SQL. The format you pick affects readability, tooling support, and what features are available. This article shows the same changeset in all four formats so you can compare them directly — then explains when each format is the right choice. The Same Change in All Four Formats To make comparison concrete, here is a single changeset — creating the users table from the e-commerce schema — written in every format.
Continue reading »Changelog Organization: Master Files, include/includeAll, Directory Structures
A single changelog file works fine for a tutorial. It stops working the moment two developers add migrations on the same day, or when you need to find the changeset that introduced a column added six months ago, or when a feature branch’s migrations must be reviewed independently before merging. Changelog organization is not a polish step — it is what determines whether Liquibase stays manageable at scale or turns into a source of merge conflicts and mystery failures.
Continue reading »Chunk-Oriented Processing: The Core Spring Batch Pattern
The read-process-write loop is at the heart of almost every Spring Batch job. Understanding exactly how it works — where transactions begin and end, what gets rolled back on failure, and how Spring Batch knows where to restart — makes everything else in the framework click into place. This article goes deep on chunk-oriented processing: the execution model, the three interfaces, the counters that track progress, and how to size chunks correctly.
Continue reading »CI/CD Integration: GitHub Actions Pipeline for Database Deployments
The Liquibase commands covered in Articles 5 and 16 become reliable only when they run automatically on every change. A developer who remembers to run futureRollbackSQL before merging is better than one who doesn’t — but a pipeline that enforces it is better than both. This article builds a complete GitHub Actions pipeline: PR validation gates that block merges when rollback is missing, a staging deployment workflow, and a production deployment workflow with mandatory tagging and pre-generated rollback files.
Continue reading »