Skip to content

Conversation

@bsayli
Copy link
Owner

@bsayli bsayli commented Oct 7, 2025

feat: modernize API response architecture with RFC 7807, dynamic generics, and pagination-aware wrappers

Closes #4 — Adopt RFC 7807 (application/problem+json) for standardized error responses
Closes #5 — Introduce generic Page schema and pagination-aware ServiceResponse wrappers

Summary:

  • Introduced dynamic generics introspection engine (AutoWrapperSchemaCustomizer) for runtime schema enrichment
  • Added vendor extensions (x-data-container, x-data-item) to support nested generics resolution
  • Unified schema registration flow to auto-detect ServiceResponse and ServiceResponse<Page> structures
  • Replaced legacy error list with RFC 7807-compliant ProblemDetail and consistent client decoding
  • Implemented generic Page model for scalable list endpoints
  • Updated application.yaml configuration to support multiple generic container types (Page, Slice, etc.)
  • Overhauled documentation (README + all adoption guides) for 0.7.0 release
  • Improved logging and configurability via app.openapi.wrapper.* properties

Result:
The project now features a fully dynamic generics-aware OpenAPI schema layer, enabling true nested type support, RFC 7807 error compliance, and pagination-ready response envelopes.

bsayli added 6 commits October 6, 2025 19:30
…ng support

### customer-service
- Implemented CustomerController with full CRUD endpoints for /v1/customers
- Added paging, sorting, and search filtering (Page, Meta, Sort abstractions)
- Introduced CustomerControllerAdvice for centralized RFC 7807 ProblemDetail error handling
  (400, 404, 500, validation, and type mismatch scenarios)
- Improved error payloads with requestId, errorCode, and violations list
- Updated CustomerServiceImpl with in-memory data store, pagination, and sorting logic

### customer-service-client
- Refactored OpenAPI templates (pojo.mustache / model.mustache) to cleanly handle
  additionalProperties imports via vendorExtensions
- Ensured generated ProblemDetail model conforms to RFC 7807 schema
- Added GlobalErrorResponsesCustomizer to inject shared problem+json responses
  (400, 404, 500) into all OpenAPI operations
- Unified schema references, imports, and codegen stability between client and server

Overall: standardized API behavior, improved OpenAPI alignment, and ensured
type-safe client generation with consistent error and response contracts.
…cs-aware client generation

# Server (customer-service)
- Add uniform RFC7807 error handling:
  - Introduced layered @RestControllerAdvice handlers:
    - ValidationExceptionHandler (400, field errors, constraint violations)
    - JsonExceptionHandler (400, unreadable/invalid JSON, unrecognized fields)
    - SpringHttpExceptionHandler (404/405/400 parameter issues)
    - ApplicationExceptionHandler (404 domain not-found, 500 fallback)
  - Centralized helpers in `ProblemSupport` (type URIs, baseProblem, attachErrors).
  - Added `ErrorItem` and `ProblemExtensions` records for structured error payloads.
- OpenAPI enrichment for errors:
  - `GlobalErrorResponsesCustomizer` injects 400/404/405/500 responses with `application/problem+json`.
  - Ensures `ProblemDetail` + `ErrorItem` schemas present (component-level).
- Common response model improvements:
  - `Page<T>` record (content, page, size, totals, hasNext/Prev).
  - `Meta` record (requestId, serverTime, sort) with helpers.
  - Constants and extension keys moved under `OpenApiSchemas`.

# OpenAPI (server-side generation metadata)
- Auto-register type-safe wrappers:
  - `AutoWrapperSchemaCustomizer` scans controller return types and adds composed
    `ServiceResponse<...>` wrappers into components.
  - Enriches wrappers with vendor extensions:
    - `x-api-wrapper`, `x-api-wrapper-datatype`
    - `x-data-container` (e.g., `Page`) and `x-data-item` (e.g., `CustomerDto`)
  - Robust resolution for `$ref`, `allOf`, and array `items` (handles 3.1 `JsonSchema`).
- Standardized extension constants in `OpenApiSchemas`.

# Client (customer-service-client)
- Strongly-typed core:
  - Introduced records:
    - `Page<T>` (immutable `content` defensive copy)
    - `ClientMeta` (immutable copy of sort list)
  - Sort model under `common.sort` package:
    - `SortField` (CUSTOMER_ID/NAME/EMAIL) and `SortDirection` (ASC/DESC) enums
    - `ClientSort` record (defaults to CUSTOMER_ID/ASC)
- Generic response base kept as class (for extension):
  - `ServiceClientResponse<T>` unchanged intentionally (can be subclassed by generated wrappers).
- Generics-aware template for generated wrappers:
  - If `x-data-container` & `x-data-item` exist, generate
    `extends ServiceClientResponse<Container<Item>>`
  - Else fallback to `extends ServiceClientResponse<Datatype>`
- Error translation for RestClient:
  - `ClientProblemException` (Serializable) wraps RFC7807 body + HTTP status.
  - `CustomerApiClientConfig` registers `RestClientCustomizer` that reads `ProblemDetail`
    from response and throws `ClientProblemException` for any non-2xx.
  - Manual application of `RestClientCustomizer`s when building `ApiClient` (test-friendly).
- Adapter API made type-safe:
  - `getCustomers(..)` now accepts `SortField` / `SortDirection` instead of raw strings,
    adapts to generated wire-level params seamlessly.

# Tests
- Unit: `CustomerClientAdapterImplTest` updated for records and typed Page.
- Integration (MockWebServer):
  - `CustomerClientIT` happy-path tests for 201/200 and Page mapping.
  - `CustomerClientErrorIT` error-path tests:
    - 404 with ProblemDetail
    - 400 validation problem (extensions.errors)
    - 500 without body (null ProblemDetail fallback)
- New unit tests for config error handler (object mapper parse + no-body case).

BREAKING CHANGES:
- Client adapter signature change:
  - `getCustomers(name, email, page, size, sortBy, direction: String)` ➜
    `getCustomers(name, email, page, size, sortBy: SortField, direction: SortDirection)`
- Generated DTO envelope classes now extend `ServiceClientResponse<...>` using container/item
  metadata; downstream code relying on previous raw wrapper generics may require minor updates.
- Sort model moved under `io.github.bsayli.openapi.client.common.sort`.

Refs:
- OpenAPI 3.1 compose/resolve support (array item `$ref`, `JsonSchema`).
- RFC7807 consistent error payloads end-to-end.
…ested generics architecture

### Why
The previous documentation described only `ServiceResponse<T>` without the new meta layer and nested generic support.

### What Changed
- Updated root README to introduce the `{ data, meta }` response structure
- Added details about full nested generic handling (`ServiceResponse<Page<T>>`)
- Revised adoption guides (server & client) to match new architecture
- Clarified OpenAPI extensions (`x-api-wrapper`, `x-data-container`, `x-data-item`)
- Improved Quick Start and examples to reflect current generator output

### Result
All docs now reflect the latest end-to-end generics-aware design and align with the production-ready OpenAPI Generator 7.16.0 setup.
… RFC 7807 alignment

- Rewrote root README.md with modern architectural overview, response flow diagram, and end-to-end example
- Updated all adoption guides under /docs/adoption:
  - server-side-adoption.md → now includes {data, meta} envelope and optional Problem extensions
  - client-side-adoption.md → fully refactored for RFC 7807 ProblemDetail decoding and RestClient integration
  - client-side-adoption-pom.md → clarified Maven plugin chain, properties, and new additionalProperties syntax
- Added consistent formatting, section numbering, and Google-style code blocks
- Unified terminology: “ServiceResponse<T> / ServiceClientResponse<T>” and “Meta” across all examples
- Refined OpenAPI 3.1 alignment (springdoc 2.8.13, generator 7.16.0, HttpClient5 5.5)
- Introduced clean architecture diagram for end-to-end client generation flow
- Improved readability and SEO structure for GitHub Pages rendering

Result: project docs now reflect the final {data, meta} response model, nested generics support, and full ProblemDetail compliance.
@bsayli bsayli self-assigned this Oct 7, 2025
@codecov-commenter
Copy link

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

@bsayli bsayli merged commit 28bdd24 into main Oct 7, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Generic Page<T> Schema and Pagination-Aware Wrapper Generation Adopt RFC 7807 (“Problem Details”) for standardized error responses

3 participants