Interview Practice

Chapter 2 of 5

HTTP boundaries, validation and security

Keep transport contracts clear while enforcing rules on the server.
Read aloud is unavailable in this browser. Reading preferences still work.

Controllers translate a protocol

A controller maps HTTP requests to application use cases and maps results/errors back to a documented response contract. Keep business invariants in services or domain objects so they apply outside one endpoint. Distinguish malformed requests, missing resources and business conflicts. A stable error representation helps clients respond without parsing arbitrary exception messages. Pagination and maximum request sizes are also part of the boundary.

Layer validation by responsibility

Boundary validation checks request shape, lengths and simple constraints. Domain validation checks business meaning. Database constraints or atomic conditional writes protect invariants under competing requests. A pre-check that a record does not exist cannot prevent two instances from simultaneously inserting it. Central exception mapping can translate known failures while logging unexpected failures without leaking secrets or stack traces to callers.

Identity does not grant every action

Authentication establishes identity, while authorization checks the requested operation and resource ownership. Enforce authorization on the server even if the browser hides a button. CORS controls browser cross-origin access and is not identity verification. Cookie/session-based authentication has different CSRF considerations from correctly handled bearer tokens; configure security according to the actual credential flow rather than disabling protections by habit.

Worked Java example

Illustrative snippet: imports, surrounding types or collaborators may be omitted. Read the assumptions before adapting it.

record CreateOrderRequest(@NotBlank String productId,
                          @Min(1) int quantity) {}
// In a registered REST controller:
@PostMapping("/orders")
ResponseEntity<OrderResponse> create(
        @Valid @RequestBody CreateOrderRequest request) {
    OrderResponse result = orders.create(request);
    return ResponseEntity.created(
        URI.create("/orders/" + result.id())).body(result);
}

Walkthrough

The snippet is a controller fragment, not a standalone application. Jakarta validation support must be configured. Validation rejects malformed quantities; orders.create must still enforce inventory, ownership and persistence invariants. The created response has a Location and body. Use a constrained or safely encoded identifier when constructing real resource URIs.

Practice it yourself

Two requests both pass an availability check for the last seat. Explain why input validation and a controller lock may still be insufficient.

Check your reasoning

Input validation does not serialize competing business operations. A lock in one instance does not cover another instance. Use a storage-enforced conditional reservation or constraint in the appropriate transaction, handle the conflict, and make retries safe.

Recall checklist

  • Explain the main invariant or contract without looking.
  • Trace the example and test an edge case.
  • State time, space, input variables and assumptions where relevant.
  • Explain one alternative and when you would choose it.

Read further