API Validation
API validation checks incoming request data at the API boundary before it reaches application logic. It rejects invalid input with predictable, client-friendly errors so downstream code can rely on established constraints.
In a Java backend, validation commonly checks request bodies, query parameters, path variables, and other externally supplied data against explicit rules. With Spring-based applications, Jakarta Bean Validation annotations such as `@NotNull`, `@NotBlank`, `@Size`, and `@Email` can express many constraints directly on DTOs.
Validation should happen near the system boundary because external input cannot be assumed to be trustworthy or correctly shaped. A controller can receive a validated DTO, allowing service-layer code to focus primarily on business rules rather than repeatedly checking basic input constraints.
Validation failures should produce a consistent HTTP response. For example, malformed or constraint-violating request data is commonly represented with a `400 Bad Request`, while the response can identify which fields failed and why. Framework exception handling can centralize this formatting instead of duplicating it across controllers.
API validation is different from business validation. A rule such as "email must not be blank" is an input constraint, while "a user cannot cancel an already completed order" depends on application state and business rules. Keeping these responsibilities distinct makes the API easier to maintain and test.
Key points
- Validate untrusted request data at the API boundary.
- Use DTOs and declarative constraints for common input rules.
- Return consistent client-facing validation errors.
- Keep input constraints separate from state-dependent business rules.
- Do not rely on client-side validation as a security boundary.
Interview questions
What is API validation and where should it happen?
API validation checks externally supplied request data against the API's expected contract. In a Java backend, it is commonly performed at the controller boundary using DTOs and Bean Validation. Rejecting invalid data early keeps service code simpler and prevents malformed input from flowing through the application. The API should also return a predictable error representation for validation failures.
How does `@Valid` work with a request DTO?
When `@Valid` is placed on a controller method parameter such as a `@RequestBody` DTO, the validation framework evaluates the constraints declared on that object's fields or record components. Constraints such as `@NotBlank` and `@Size` define the expected input rules. If a constraint fails, the framework can raise a validation-related exception before normal controller processing completes. An exception handler can then turn that failure into the application's standard error response.
What is the difference between `@NotNull`, `@NotEmpty`, and `@NotBlank`?
`@NotNull` only requires that the value is not null. `@NotEmpty` additionally requires a non-empty supported container or string, while `@NotBlank` is intended for strings and rejects values that contain only whitespace. The choice should match the semantic requirement of the field. For example, a required human-readable name commonly uses `@NotBlank`.
How would you design a consistent validation error response?
I would define one error representation containing enough information for clients to understand and display the failure. For field validation, that can include the field name and a stable error code or message. I would handle validation exceptions centrally so controllers do not each implement their own response formatting. The format should remain consistent across endpoints and should avoid exposing unnecessary internal details.
Why should API validation and business validation be separated?
They answer different questions. API validation determines whether the request conforms to the input contract, while business validation determines whether the requested operation is valid given application state and domain rules. Mixing them can make controllers contain complex domain logic and can make rules harder to reuse. A clean design can validate structural input at the boundary and enforce domain invariants in the service or domain layer.