Skip to content

Commit 0fc6a98

Browse files
committed
docs(client): refine README and adoption guides; clarify examples
- customer-service-client README: production-ready HttpClient5 wiring as recommended path - add Client-Side Integration Guide and POM setup docs with working links - fix usage example imports to reduce FQN noise templates: switch wrapper to import-based template - api_wrapper.mustache: use `import {{commonPackage}}.ServiceClientResponse` - keep x-class-extra-annotation hook chore: minor wording/links, consistency across module docs
1 parent 62621f7 commit 0fc6a98

File tree

6 files changed

+198
-99
lines changed

6 files changed

+198
-99
lines changed

customer-service-client/README.md

Lines changed: 92 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ curl -s http://localhost:8084/customer-service/v3/api-docs.yaml \
2828
mvn -q clean install
2929
```
3030

31-
Generated sources → `target/generated-sources/openapi/src/gen/java`
31+
*Generated sources → `target/generated-sources/openapi/src/gen/java`*
32+
33+
> ℹ️ **Multi-module builds:** If your project is multi-module, ensure the generated path is compiled via
34+
`build-helper-maven-plugin` (already configured in this repo’s `pom.xml`).
3235

3336
---
3437

@@ -89,6 +92,14 @@ To apply the same approach in your own project:
8992
> ⚠️ **Do not add `customer-service-client` as a Maven/Gradle dependency in your project.**
9093
> Instead, re-generate your own client using **your service’s OpenAPI spec** and the provided Mustache templates.
9194
95+
## 📘 Adoption Guides
96+
97+
Looking to integrate this approach into your own project?
98+
See the detailed guides under [`docs/adoption`](../docs/adoption):
99+
100+
- [Server-Side Adoption](../docs/adoption/server-side-adoption.md)
101+
- [Client-Side Adoption](../docs/adoption/client-side-adoption.md)
102+
92103
---
93104

94105
## 📦 Prerequisites
@@ -157,9 +168,12 @@ Consumer code (e.g., adapter) gets compile-time type safety
157168

158169
## 🧰 Troubleshooting (quick)
159170

160-
* **No thin wrappers generated?**
161-
Check your spec contains vendor extensions on wrapper schemas (look for `x-api-wrapper: true`).
162-
Also verify the generator uses your overlay via `<templateDirectory>`.
171+
* **No thin wrappers generated?**
172+
Ensure wrapper schemas in your OpenAPI spec include the vendor extensions:
173+
`x-api-wrapper: true` and `x-api-wrapper-datatype`.
174+
Confirm your generator points to the correct `<templateDirectory>` **and** that effective templates are copied (see
175+
the `maven-dependency-plugin` + `maven-resources-plugin` steps).
176+
If unsure, delete `target/` and run `mvn clean install`.
163177

164178
* **Wrong packages or missing classes?**
165179
Ensure `apiPackage`, `modelPackage`, and `invokerPackage` in the plugin configuration match what you expect.
@@ -186,32 +200,37 @@ Consumer code (e.g., adapter) gets compile-time type safety
186200

187201
## 🧩 Using the Client
188202

189-
### Option A — Spring Configuration (recommended)
203+
### Option A — Quick Start (simple RestClient for demos/dev)
190204

191205
```java
192206

193-
@Configuration
194-
public class CustomerApiClientConfig {
207+
package your.pkg;
195208

196-
@Bean
197-
public RestClient customerRestClient(RestClient.Builder builder,
198-
@Value("${customer.api.base-url}") String baseUrl) {
199-
return builder.baseUrl(baseUrl).build();
200-
}
209+
import io.github.bsayli.openapi.client.generated.api.CustomerControllerApi;
210+
import io.github.bsayli.openapi.client.generated.invoker.ApiClient;
211+
import org.springframework.beans.factory.annotation.Value;
212+
import org.springframework.context.annotation.Bean;
213+
import org.springframework.context.annotation.Configuration;
214+
import org.springframework.web.client.RestClient;
201215

202-
@Bean
203-
public io.github.bsayli.openapi.client.generated.invoker.ApiClient customerApiClient(
204-
RestClient customerRestClient,
205-
@Value("${customer.api.base-url}") String baseUrl) {
206-
return new io.github.bsayli.openapi.client.generated.invoker.ApiClient(customerRestClient)
207-
.setBasePath(baseUrl);
208-
}
216+
@Configuration
217+
public class CustomerApiClientConfig {
209218

210-
@Bean
211-
public io.github.bsayli.openapi.client.generated.api.CustomerControllerApi customerControllerApi(
212-
io.github.bsayli.openapi.client.generated.invoker.ApiClient apiClient) {
213-
return new io.github.bsayli.openapi.client.generated.api.CustomerControllerApi(apiClient);
214-
}
219+
@Bean
220+
RestClient customerRestClient(RestClient.Builder builder) {
221+
return builder.build();
222+
}
223+
224+
@Bean
225+
ApiClient customerApiClient(RestClient customerRestClient,
226+
@Value("${customer.api.base-url}") String baseUrl) {
227+
return new ApiClient(customerRestClient).setBasePath(baseUrl);
228+
}
229+
230+
@Bean
231+
CustomerControllerApi customerControllerApi(ApiClient customerApiClient) {
232+
return new CustomerControllerApi(customerApiClient);
233+
}
215234
}
216235
```
217236

@@ -224,19 +243,32 @@ customer.api.base-url=http://localhost:8084/customer-service
224243
**Usage example:**
225244

226245
```java
246+
import io.github.bsayli.openapi.client.generated.api.CustomerControllerApi;
247+
import io.github.bsayli.openapi.client.generated.dto.CustomerCreateRequest;
248+
import io.github.bsayli.openapi.client.generated.dto.CustomerCreateResponse;
249+
import io.github.bsayli.openapi.client.common.ServiceClientResponse;
250+
import org.springframework.beans.factory.annotation.Autowired;
251+
import org.springframework.stereotype.Component;
227252

228-
@Autowired
229-
private io.github.bsayli.openapi.client.generated.api.CustomerControllerApi customerApi;
253+
@Component
254+
public class CustomerClientExample {
230255

231-
public void createCustomer() {
232-
var req = new io.github.bsayli.openapi.client.generated.dto.CustomerCreateRequest()
256+
private final CustomerControllerApi customerApi;
257+
258+
public CustomerClientExample(CustomerControllerApi customerApi) {
259+
this.customerApi = customerApi;
260+
}
261+
262+
public void createCustomer() {
263+
CustomerCreateRequest req = new CustomerCreateRequest()
233264
.name("Jane Doe")
234265
.email("jane@example.com");
235266

236-
var resp = customerApi.createCustomer(req); // ServiceResponseCustomerCreateResponse
267+
ServiceClientResponse<CustomerCreateResponse> resp = customerApi.createCustomer(req);
237268

238269
System.out.println(resp.getStatus()); // 201
239270
System.out.println(resp.getData().getCustomer().getName()); // "Jane Doe"
271+
}
240272
}
241273
```
242274

@@ -246,11 +278,22 @@ public void createCustomer() {
246278
247279
---
248280

249-
### Option A.2Alternative with HttpClient5 (connection pooling)
281+
### Option BRecommended (production-ready with HttpClient5 pooling)
250282

251283
If you want more control (connection pooling, timeouts, etc.), you can wire the client with **Apache HttpClient5**:
252284

253285
```java
286+
import io.github.bsayli.openapi.client.generated.api.CustomerControllerApi;
287+
import io.github.bsayli.openapi.client.generated.invoker.ApiClient;
288+
import java.time.Duration;
289+
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
290+
import org.apache.hc.client5.http.impl.classic.HttpClients;
291+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
292+
import org.springframework.beans.factory.annotation.Value;
293+
import org.springframework.context.annotation.Bean;
294+
import org.springframework.context.annotation.Configuration;
295+
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
296+
import org.springframework.web.client.RestClient;
254297

255298
@Configuration
256299
public class CustomerApiClientConfig {
@@ -301,15 +344,31 @@ public class CustomerApiClientConfig {
301344
}
302345

303346
@Bean
304-
CustomerControllerApi customerControllerApi(ApiClient apiClient) {
305-
return new CustomerControllerApi(apiClient);
347+
CustomerControllerApi customerControllerApi(ApiClient customerApiClient) {
348+
return new CustomerControllerApi(customerApiClient);
306349
}
307350
}
308351
```
309352

353+
> **Requires:** `org.apache.httpcomponents.client5:httpclient5` (already included in this module).
354+
355+
**application.properties:**
356+
357+
```properties
358+
# Base URL
359+
customer.api.base-url=http://localhost:8084/customer-service
360+
# HttpClient5 pool settings
361+
customer.api.max-connections-total=64
362+
customer.api.max-connections-per-route=16
363+
# Timeouts (in seconds)
364+
customer.api.connect-timeout-seconds=10
365+
customer.api.connection-request-timeout-seconds=10
366+
customer.api.read-timeout-seconds=15
367+
```
368+
310369
---
311370

312-
### Option B — Manual Wiring (no Spring context)
371+
### Option C — Manual Wiring (no Spring context)
313372

314373
```java
315374
var rest = RestClient.builder().baseUrl("http://localhost:8084/customer-service").build();
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import {{commonPackage}}.ServiceClientResponse;
2+
13
{{#vendorExtensions.x-class-extra-annotation}}
24
{{{vendorExtensions.x-class-extra-annotation}}}
35
{{/vendorExtensions.x-class-extra-annotation}}
46
public class {{classname}}
5-
extends {{commonPackage}}.ServiceClientResponse<{{vendorExtensions.x-api-wrapper-datatype}}> {
7+
extends ServiceClientResponse<{{vendorExtensions.x-api-wrapper-datatype}}> {
68
}

customer-service/README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,17 @@ against.
2525

2626
## 📊 Architecture at a Glance
2727

28-
```text
29-
client <--> customer-service <--> OpenAPI Spec (YAML/JSON) <--> customer-service-client
28+
```
29+
Client
30+
31+
32+
Customer Service
33+
34+
35+
OpenAPI Spec (YAML/JSON)
36+
37+
38+
Customer Service Client
3039
```
3140

3241
This module defines the contract; the client module consumes it.

docs/adoption/client-side-adoption-pom.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Client-Side Build Setup (Maven Plugins & Dependencies)
22

3-
When adopting the **generics-aware OpenAPI client**, make sure to configure your `pom.xml` with the required plugins and dependencies. These ensure that template overlays are applied correctly and generated sources are compiled into your project.
3+
When adopting the **generics-aware OpenAPI client**, make sure to configure your `pom.xml` with the required plugins and
4+
dependencies. These ensure that template overlays are applied correctly and generated sources are compiled into your
5+
project.
46

57
---
68

@@ -53,7 +55,8 @@ Add these dependencies to your client module:
5355

5456
## 2) Maven Plugins
5557

56-
These plugins **work together** to unpack upstream templates, overlay your custom Mustache files, and generate type-safe client code.
58+
These plugins **work together** to unpack upstream templates, overlay your custom Mustache files, and generate type-safe
59+
client code.
5760

5861
```xml
5962
<build>
@@ -193,4 +196,5 @@ These plugins **work together** to unpack upstream templates, overlay your custo
193196
* **openapi-generator-maven-plugin** → generates the client code.
194197
* **build-helper-maven-plugin** → makes sure generated code is compiled.
195198

196-
Together, these steps ensure **your generics-aware wrappers** are generated correctly and seamlessly integrated into the build.
199+
Together, these steps ensure **your generics-aware wrappers** are generated correctly and seamlessly integrated into the
200+
build.

0 commit comments

Comments
 (0)