|
16 | 16 | <em><strong>End-to-end generics-aware OpenAPI clients</strong> — unified <code>{ data, meta }</code> responses without boilerplate.</em> |
17 | 17 | </p> |
18 | 18 |
|
19 | | -**Modern, type-safe OpenAPI client generation** — powered by **Spring Boot 3.4**, **Java 21**, and **OpenAPI Generator 7.16.0**. |
20 | | -This repository demonstrates a production-grade architecture where backend and client are fully aligned through generics, enabling nested generic envelopes (`ServiceResponse<Page<T>>`) and [**RFC 9457 — Problem Details for HTTP APIs**](https://www.rfc-editor.org/rfc/rfc9457)-based error handling. |
| 19 | +**Modern, type-safe OpenAPI client generation** — powered by **Spring Boot 3.4**, **Java 21**, and **OpenAPI Generator 7.16.0**. |
| 20 | +This repository demonstrates a production-grade setup where backend and client remain fully aligned through generics, supporting nested envelopes like `ServiceResponse<Page<T>>` and standardized [**RFC 9457 — Problem Details for HTTP APIs**](https://www.rfc-editor.org/rfc/rfc9457) error handling. |
21 | 21 |
|
22 | | -> 🧠 **RFC 9457 vs RFC 7807** |
23 | | -> RFC 9457 supersedes 7807 and standardizes `application/problem+json` / `application/problem+xml` for HTTP APIs. |
24 | | -> Spring Framework 6+ implements this via the built-in `ProblemDetail` class, enabling consistent error serialization across server and client. |
| 22 | +> 🧠 **RFC 9457 vs RFC 7807** |
| 23 | +> RFC 9457 supersedes 7807 and formalizes `application/problem+json` / `application/problem+xml` for HTTP APIs. |
| 24 | +> Spring Framework 6+ natively supports this via the built-in `ProblemDetail` class, ensuring consistent error serialization between server and client. |
25 | 25 |
|
26 | 26 | --- |
27 | 27 |
|
@@ -57,19 +57,33 @@ OpenAPI Generator, by default, does not handle **generic response types**. |
57 | 57 |
|
58 | 58 | When backend APIs wrap payloads in `ServiceResponse<T>` (e.g., the unified `{ data, meta }` envelope), the generator produces **duplicated models per endpoint** instead of a single reusable generic base. |
59 | 59 |
|
60 | | -This results in: |
| 60 | +This leads to: |
61 | 61 |
|
62 | 62 | * ❌ Dozens of almost-identical response classes |
63 | 63 | * ❌ Higher maintenance overhead |
64 | 64 | * ❌ Harder to evolve a single envelope contract across services |
65 | 65 |
|
66 | 66 | ```java |
67 | 67 | // Default OpenAPI output (before) |
68 | | -class CreateCustomerResponse { CustomerDto data; Meta meta; } |
69 | | -class UpdateCustomerResponse { CustomerDto data; Meta meta; } |
| 68 | +public class ServiceResponseCustomerDto { |
| 69 | + private CustomerDto data; |
| 70 | + private Meta meta; |
| 71 | +} |
| 72 | + |
| 73 | +public class ServiceResponsePageCustomerDto { |
| 74 | + private PageCustomerDto data; // instead of Page<CustomerDto> |
| 75 | + private Meta meta; |
| 76 | +} |
| 77 | + |
| 78 | +public class ServiceResponseCustomerDeleteResponse { |
| 79 | + private CustomerDeleteResponse data; |
| 80 | + private Meta meta; |
| 81 | +} |
70 | 82 | // ... dozens of duplicates |
71 | 83 | ``` |
72 | 84 |
|
| 85 | +By applying a **Mustache overlay**, these are replaced by thin wrappers extending a single generic base (`ServiceClientResponse<T>`), preserving `Page<T>` and ensuring consistent, type-safe API clients. |
| 86 | + |
73 | 87 | --- |
74 | 88 |
|
75 | 89 | ## 💡 Solution Overview |
|
0 commit comments