REST API Conventions

1. Purpose

The one page to read before adding or changing a REST endpoint in admin-service. It states each rule briefly and links to the page that owns the detail. It exists because these conventions were, until now, implicit — and an endpoint that quietly diverged (GET /api/race-numbers/stock returning a Spring Page instead of a bare array) shipped a broken stock list and an empty UNFIT report to stage before anyone noticed.

This is a hub, not a re-explanation: where a rule has an authoritative page it links, rather than restating it.

2. Collections and pagination

  • A list endpoint returns a bare JSON array of the DTO as its body; the handler signature is ResponseEntity<List<DTO>>. Pagination metadata travels in headers — X-Total-Count and Link — via PaginationUtil.generatePaginationHttpHeaders.

  • Never return Page<T>, or any envelope object, as the response body. This is the ruling and rationale of ADR-0013, enforced by an ArchUnit test.

  • Reference implementation: RaceNumberResource.getAllRaceNumbers. Anti-pattern: RaceNumberResourceEx.stockView (returns a Page — under remediation).

3. Filtering, sorting, paging

  • Filters use the JHipster criteria grammar — ?field.equals= / .in= / .contains= / .greaterThanOrEqual= / .lessThanOrEqual= / .specified= — plus page / size / sort=field,dir.

  • Each criterion resolves through a JPA Specification in a query service. See Filterable List Pattern (the URL contract) and Query Services (where resolution lives).

  • Expose only the filters you intend. Each criterion is a queryable — and potentially unindexed — surface; do not blanket-expose every entity field.

4. Enums on the wire

  • Responses carry the constant name; the database column and an accepted filter value carry the short code; filter values resolve strictly — accept the code or the name, reject anything else with 400, never a silent default. Full rules and the resolver pattern: Enum Modelling.

  • Because responses serialise the name, renaming a constant is a breaking wire change for consumers, even though it is database-safe.

5. HTTP status contracts

  • Declare every reachable non-2xx response with @ApiResponses, and restate the success code — Javadoc does not reach the published spec, and @ApiResponses replaces springdoc’s default rather than merging with it. See OpenAPI Contract Flow → Response Contracts.

6. DTOs and errors

  • Endpoints expose MapStruct DTOs, never entities; enums cross as identity copies (see Enum Modelling).

  • Errors are RFC-7807 problem+json rendered by ExceptionTranslator. Raise ServiceBadRequestException from the service layer (not the web-layer BadRequestAlertException, which ArchTest forbids the service package from importing) for a structured 400.

8. Change History

Date Change

2026-09-01

Initial version. Consolidates the collection contract (ADR-0013), filtering, enum wire format, status-code and error conventions into one entry point.