Skip to content

Commit c45dc49

Browse files
committed
docs: add adoption guides and update root README
- Added server-side-adoption.md and client-side-adoption.md under docs/adoption - Updated root README with links to adoption guides - Extended Table of Contents for better navigation
1 parent 3797e58 commit c45dc49

File tree

3 files changed

+713
-1
lines changed

3 files changed

+713
-1
lines changed

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ duplicated wrappers, and keep client code clean.
3333
-[Key Features](#-key-features)
3434
-[Usage Example](#-usage-example-adapter-interface)
3535
- 📦 [Related Modules](#-related-modules-quick-view)
36+
- 📘 [Adoption Guides](#-adoption-guides)
3637

3738
### 📦 Modules in this Repository
3839

@@ -343,4 +344,14 @@ If you found this project useful, please consider giving it a star ⭐ on GitHub
343344
| Module | Description | Docs |
344345
|--------------------------------|---------------------------------------------|---------------------------------------------|
345346
| 🟢 **customer-service** | Spring Boot sample API (producer) | [README](customer-service/README.md) |
346-
| 🔵 **customer-service-client** | Generated Java client with generics support | [README](customer-service-client/README.md) |
347+
| 🔵 **customer-service-client** | Generated Java client with generics support | [README](customer-service-client/README.md) |
348+
349+
---
350+
351+
## 📘 Adoption Guides
352+
353+
Looking to integrate this approach into your own project?
354+
See the detailed guides under [`docs/adoption`](docs/adoption):
355+
356+
- [Server-Side Adoption](docs/adoption/server-side-adoption.md)
357+
- [Client-Side Adoption](docs/adoption/client-side-adoption.md)
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Client-Side Integration Guide
2+
3+
This document describes how to integrate the **generics-aware OpenAPI client** into your own microservice project, based on the patterns demonstrated in the `customer-service-client` module.
4+
5+
The purpose is to generate **type-safe clients** that extend a reusable generic base (`ServiceClientResponse<T>`) instead of duplicating response envelopes.
6+
7+
---
8+
9+
## 1) What You Get
10+
11+
* Thin wrappers per endpoint (`ServiceResponseYourDto`), each extending `ServiceClientResponse<T>`.
12+
* Strong typing for `getData()` without boilerplate or casting.
13+
* A reusable adapter interface to keep generated code isolated.
14+
* Optional Spring Boot configuration to auto-wire the client beans.
15+
16+
---
17+
18+
## 2) Prerequisites
19+
20+
* Java 21+
21+
* Maven 3.9+ (or Gradle 8+ if adapted)
22+
* Running service exposing `/v3/api-docs.yaml`
23+
24+
---
25+
26+
## 3) Steps to Generate
27+
28+
1. **Pull the OpenAPI spec** from your service:
29+
30+
```bash
31+
curl -s http://localhost:8084/your-service/v3/api-docs.yaml \
32+
-o src/main/resources/your-api-docs.yaml
33+
```
34+
35+
2. **Run Maven build** in the client module:
36+
37+
```bash
38+
mvn clean install
39+
```
40+
41+
3. **Inspect generated code**:
42+
43+
* `target/generated-sources/openapi/src/gen/java`
44+
* Look for classes like `ServiceResponseYourDto` extending `ServiceClientResponse<YourDto>`
45+
46+
---
47+
48+
## 4) Core Classes to Copy
49+
50+
Ensure you copy the following **shared classes** into your client project:
51+
52+
**`common/ServiceClientResponse.java`**
53+
54+
```java
55+
package <your.base>.openapi.client.common;
56+
57+
import java.util.List;
58+
import java.util.Objects;
59+
60+
public class ServiceClientResponse<T> {
61+
private Integer status;
62+
private String message;
63+
private List<ClientErrorDetail> errors;
64+
private T data;
65+
// getters, setters, equals, hashCode, toString
66+
}
67+
```
68+
69+
**`common/ClientErrorDetail.java`**
70+
71+
```java
72+
package <your.base>.openapi.client.common;
73+
74+
public record ClientErrorDetail(String errorCode, String message) {}
75+
```
76+
77+
These are referenced by the Mustache templates and must exist in your client project.
78+
79+
---
80+
81+
## 5) Mustache Templates
82+
83+
Place the following templates under:
84+
85+
```
86+
src/main/resources/openapi-templates/
87+
```
88+
89+
**`api_wrapper.mustache`**
90+
91+
```mustache
92+
{{#vendorExtensions.x-class-extra-annotation}}
93+
{{{vendorExtensions.x-class-extra-annotation}}}
94+
{{/vendorExtensions.x-class-extra-annotation}}
95+
public class {{classname}}
96+
extends {{commonPackage}}.ServiceClientResponse<{{vendorExtensions.x-api-wrapper-datatype}}> {
97+
}
98+
```
99+
100+
**`model.mustache`** (partial overlay to delegate wrapper classes to `api_wrapper.mustache`).
101+
102+
These ensure generated wrappers extend the generic base instead of duplicating fields.
103+
104+
---
105+
106+
## 6) Adapter Pattern
107+
108+
Encapsulate generated APIs in an adapter interface:
109+
110+
```java
111+
package <your.base>.openapi.client.adapter;
112+
113+
import <your.base>.openapi.client.common.ServiceClientResponse;
114+
import <your.base>.openapi.client.generated.dto.*;
115+
116+
public interface YourClientAdapter {
117+
ServiceClientResponse<YourDto> getYourEntity(Integer id);
118+
ServiceClientResponse<YourCreateResponse> createYourEntity(YourCreateRequest request);
119+
}
120+
```
121+
122+
This shields your business code from generated artifacts and provides a stable contract.
123+
124+
---
125+
126+
## 7) Spring Boot Configuration (Optional)
127+
128+
Example auto-wiring configuration:
129+
130+
```java
131+
@Configuration
132+
public class YourApiClientConfig {
133+
134+
@Bean
135+
RestClient yourRestClient(RestClient.Builder builder,
136+
@Value("${your.api.base-url}") String baseUrl) {
137+
return builder.baseUrl(baseUrl).build();
138+
}
139+
140+
@Bean
141+
ApiClient yourApiClient(RestClient yourRestClient,
142+
@Value("${your.api.base-url}") String baseUrl) {
143+
return new ApiClient(yourRestClient).setBasePath(baseUrl);
144+
}
145+
146+
@Bean
147+
YourControllerApi yourControllerApi(ApiClient apiClient) {
148+
return new YourControllerApi(apiClient);
149+
}
150+
}
151+
```
152+
153+
**application.properties:**
154+
155+
```properties
156+
your.api.base-url=http://localhost:8084/your-service
157+
```
158+
159+
---
160+
161+
## 8) Usage Example
162+
163+
```java
164+
@Autowired
165+
private YourControllerApi yourApi;
166+
167+
public void demo() {
168+
var req = new YourCreateRequest().name("Alice");
169+
var resp = yourApi.createYourEntity(req);
170+
System.out.println(resp.getStatus());
171+
System.out.println(resp.getData().getName());
172+
}
173+
```
174+
175+
---
176+
177+
## 9) Notes
178+
179+
* Dependencies like `spring-web`, `jakarta.*` are often marked **provided** — your host app must supply them.
180+
* Re-run `curl` + `mvn clean install` whenever your service’s OpenAPI spec changes.
181+
* Optional vendor extension `x-class-extra-annotation` can add annotations (e.g., Jackson or Lombok) on generated wrappers.
182+
183+
---
184+
185+
## 10) Folder Structure (Suggested)
186+
187+
```
188+
your-service-client/
189+
├─ src/main/java/<your/base>/openapi/client/common/
190+
│ ├─ ServiceClientResponse.java
191+
│ └─ ClientErrorDetail.java
192+
├─ src/main/java/<your/base>/openapi/client/adapter/
193+
│ └─ YourClientAdapter.java
194+
├─ src/main/resources/openapi-templates/
195+
│ ├─ api_wrapper.mustache
196+
│ └─ model.mustache
197+
├─ src/main/resources/your-api-docs.yaml
198+
└─ pom.xml
199+
```
200+
201+
---
202+
203+
✅ With this setup, your client project generates **type-safe wrappers** that align with `ServiceResponse<T>` from the server side, without any boilerplate duplication.

0 commit comments

Comments
 (0)