Skip to content

Commit be55cc3

Browse files
authored
Merge pull request #19 from blueprint-platform/release/1.0.0
Release/1.0.0 feat: BYOE (Bring Your Own Envelope) support + pipeline refinement + documentation simplification
2 parents b52c756 + 2fdfed5 commit be55cc3

108 files changed

Lines changed: 5040 additions & 6044 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 187 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
## 📑 Table of Contents
2828

2929
*[Why this exists (practical impact)](#why-this-exists-practical-impact)
30-
* 🆕 [What’s new in 0.9.x](#whats-new-in-09x)
30+
* 🆕 [What’s new in 1.0.0 (GA)](#whats-new-in-100-ga)
3131
*[Real usage (what you actually do)](#real-usage-what-you-actually-do)
3232
*[Quick start (2 minutes)](#quick-start-2-minutes)
3333
* 🔁 [Contract lifecycle model](#contract-lifecycle-model)
@@ -62,21 +62,112 @@ This project removes that entire class of problems.
6262
6363
---
6464

65-
## What’s new in 0.9.x
65+
## What’s new in 1.0.0 (GA)
6666

6767
This is no longer a template-level customization.
6868

69-
It is now a **contract-aligned generation system with progressive adoption**.
69+
It is now a **contract-aligned generation system with progressive adoption** — designed to adapt to existing architectures instead of forcing new ones.
7070

71-
### 1. Bring Your Own Contract (BYOC)
71+
---
72+
73+
### 1. Bring Your Own Envelope (BYOE)
74+
75+
Use your **existing response envelope** without migrating to `ServiceResponse`.
76+
77+
```xml
78+
<additionalProperties>
79+
<additionalProperty>
80+
openapi-generics.envelope=io.example.contract.ApiResponse
81+
</additionalProperty>
82+
</additionalProperties>
83+
```
84+
85+
Result:
86+
87+
* no forced migration to a new envelope type
88+
* your response model remains intact
89+
* existing contracts continue to work as-is
90+
91+
Behavior:
92+
93+
* If not configured → `ServiceResponse<T>` is used (default)
94+
* If configured → your envelope type becomes the base of generated wrappers
95+
96+
This removes the most common adoption blocker:
97+
98+
> "Do we need to change our response model to use this?"
99+
100+
Answer: **No.**
101+
102+
---
103+
104+
#### How it works
105+
106+
The platform does not generate your envelope.
107+
108+
It **reuses it as a contract dependency** — both on the server and client side.
109+
110+
Two usage paths are supported:
111+
112+
**1. Springdoc-based (automatic)**
113+
114+
* Server starter detects your envelope
115+
* OpenAPI is enriched with required semantics automatically
116+
* No manual schema work is required
117+
118+
**2. Spec-first / manual OpenAPI**
119+
120+
* Teams can define wrapper schemas directly in OpenAPI
121+
* The wrapper expresses the relationship between the envelope and the payload
122+
* Minimal semantics are added to indicate that the schema represents a generic wrapper
123+
* Client generation reconstructs the correct generic structure from this definition
124+
125+
Example (simplified):
126+
127+
```yaml
128+
ApiResponseLicenseAccessResponse:
129+
type: object
130+
properties:
131+
data:
132+
$ref: "#/components/schemas/LicenseAccessResponse"
133+
x-api-wrapper: true
134+
x-api-wrapper-datatype: LicenseAccessResponse
135+
```
136+
137+
Optional: internal envelope-related models can be marked to avoid regeneration:
138+
139+
```yaml
140+
ApiError:
141+
type: object
142+
properties:
143+
errorCode:
144+
type: string
145+
message:
146+
type: string
147+
x-ignore-model: true
148+
```
149+
150+
> Springdoc is the easiest path — not the only one.
151+
152+
In both approaches, the outcome is the same:
153+
154+
* the envelope remains your contract
155+
* OpenAPI acts as a projection
156+
* generated clients preserve the original type structure
157+
158+
> Note: BYOE currently supports flat generic envelopes (e.g. `YourEnvelope<T>`).
159+
> More complex or nested generic shapes follow the platform’s default contract behavior.
160+
161+
---
162+
163+
### 2. Bring Your Own Contract (BYOC)
72164

73165
Reuse your own domain models instead of generating them:
74166

75167
```xml
76-
<!-- Map your DTOs to existing contract classes -->
77168
<additionalProperties>
78169
<additionalProperty>
79-
openapiGenerics.responseContract.CustomerDto=io.example.contract.CustomerDto
170+
openapi-generics.response-contract.CustomerDto=io.example.contract.CustomerDto
80171
</additionalProperty>
81172
</additionalProperties>
82173
```
@@ -88,7 +179,7 @@ Result:
88179

89180
---
90181

91-
### 2. Progressive adoption (client-side only)
182+
### 3. Progressive adoption (client-side only)
92183

93184
Switch generation modes through the client build configuration:
94185

@@ -103,7 +194,7 @@ Switch generation modes through the client build configuration:
103194

104195
---
105196

106-
### 3. Deterministic build pipeline
197+
### 4. Deterministic build pipeline
107198

108199
Client generation is a **controlled execution system**:
109200

@@ -113,7 +204,7 @@ Client generation is a **controlled execution system**:
113204

114205
---
115206

116-
### 4. End-to-end samples (Spring Boot 3 & 4)
207+
### 5. End-to-end samples (Spring Boot 3 & 4)
117208

118209
Full pipelines are included:
119210

@@ -139,7 +230,7 @@ You only add two building blocks.
139230
<dependency>
140231
<groupId>io.github.blueprintplatform</groupId>
141232
<artifactId>openapi-generics-server-starter</artifactId>
142-
<version>0.9.0</version>
233+
<version>1.0.0</version>
143234
</dependency>
144235
```
145236

@@ -149,7 +240,7 @@ You only add two building blocks.
149240
<parent>
150241
<groupId>io.github.blueprintplatform</groupId>
151242
<artifactId>openapi-generics-java-codegen-parent</artifactId>
152-
<version>0.9.0</version>
243+
<version>1.0.0</version>
153244
</parent>
154245
```
155246

@@ -225,17 +316,97 @@ Client (contract-aligned)
225316
The response envelope is a **shared contract**, not a generated model.
226317

227318
```text
228-
ServiceResponse<T>
319+
YourEnvelope<T>
229320
```
230321

231-
Supported:
322+
> `ServiceResponse<T>` is the **default contract provided by the platform** — not a restriction.
323+
324+
The system is designed around a simple principle:
325+
326+
> Define your contract once. Preserve it end-to-end.
327+
328+
---
329+
330+
### What this means in practice
331+
332+
* The response envelope is **not regenerated per endpoint**
333+
* The same contract is reused across:
334+
335+
* server responses
336+
* OpenAPI projection
337+
* generated clients
338+
* Client models **extend the contract**, instead of redefining it
339+
340+
Result:
341+
342+
* no envelope duplication
343+
* no drift between server and client
344+
* a stable, predictable type system
345+
346+
---
347+
348+
### Supported shapes (deterministic scope)
232349

233350
```text
234351
ServiceResponse<T>
235352
ServiceResponse<Page<T>>
353+
YourEnvelope<T>
236354
```
237355

238-
Other cases follow standard OpenAPI behavior.
356+
These shapes are **explicitly supported and enforced** to guarantee:
357+
358+
* deterministic OpenAPI generation
359+
* predictable client reconstruction
360+
* zero ambiguity in generic resolution
361+
362+
> Note: Custom envelopes (BYOE) currently support a single direct generic payload (e.g. `YourEnvelope<T>`).
363+
> Nested generic payloads (e.g. `YourEnvelope<Page<T>>`) are intentionally out of scope.
364+
365+
---
366+
367+
### Important: default ≠ mandatory
368+
369+
While `ServiceResponse<T>` is the canonical default, the platform does **not require you to use it**.
370+
371+
With BYOE (Bring Your Own Envelope):
372+
373+
```text
374+
YourEnvelope<T>
375+
```
376+
377+
can be used instead, without changing the overall model.
378+
379+
The behavior remains the same:
380+
381+
* OpenAPI is still a projection
382+
* Generics are still preserved
383+
* Clients still reconstruct the contract shape
384+
385+
---
386+
387+
### Boundary of the system
388+
389+
Outside the supported shapes, the system intentionally falls back to standard OpenAPI behavior.
390+
391+
This is a **deliberate design decision**:
392+
393+
* keeps the model simple and predictable
394+
* avoids partial or misleading generics support
395+
* ensures long-term stability of generated clients
396+
397+
---
398+
399+
### Mental model
400+
401+
```text
402+
Contract (Java) → Projection (OpenAPI) → Reconstruction (Client)
403+
```
404+
405+
The envelope is the anchor of this flow.
406+
407+
It is not something the generator invents —
408+
409+
it is something the system preserves.
239410

240411
---
241412

@@ -289,9 +460,10 @@ public class ServiceResponsePageCustomerDto
289460
## Design guarantees
290461

291462
* ✔ Contract identity is preserved
463+
* ✔ Contract ownership is preserved (including the response envelope)
292464
* ✔ Generics are preserved (within supported scope)
293465
* ✔ Client generation is deterministic
294-
*External models are reusable
466+
* ✔ No contract duplication (external models are reused, not regenerated)
295467
* ✔ Upstream drift is detected early
296468

297469
---

SECURITY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ We currently provide security fixes for the latest minor release line and the `m
2828
|-----------| --------------- |
2929
| `main` | ✅ Supported |
3030
| `0.9.x` | ✅ Supported |
31-
| `< 0.9.0` | ❌ Not supported |
31+
| `< 1.0.0` | ❌ Not supported |
3232

3333
> **Note**
3434
> This project is **pre-1.0**. Public APIs and contracts may evolve quickly.

0 commit comments

Comments
 (0)