Skip to content

Commit 22bf6cf

Browse files
committed
add response-interface documentation (openapi-processor/openapi-processor-base#247)
1 parent 84986f9 commit 22bf6cf

File tree

2 files changed

+180
-26
lines changed

2 files changed

+180
-26
lines changed

docs/modules/ROOT/pages/processor/configuration.adoc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A mapping yaml looks like this:
99

1010
[source,yaml]
1111
----
12-
openapi-processor-mapping: v11
12+
openapi-processor-mapping: v12
1313
1414
options:
1515
package-name: io.openapiprocessor.sample
@@ -60,7 +60,7 @@ Interfaces and models will be generated into the `api` and `model` subpackages o
6060

6161
[source,yaml]
6262
----
63-
openapi-processor-mapping: v11
63+
openapi-processor-mapping: v12
6464
6565
options:
6666
package-name: io.openapiprocessor.sample
@@ -117,7 +117,7 @@ components:
117117
*mapping.yaml*
118118
[source,yaml]
119119
----
120-
openapi-processor-mapping: v11
120+
openapi-processor-mapping: v12
121121
122122
options:
123123
package-name: io.openapiprocessor.sample
@@ -169,7 +169,7 @@ generate pojos (class with get/set property methods) or records model classes fr
169169
*mapping.yaml*
170170
[source,yaml]
171171
----
172-
openapi-processor-mapping: v11
172+
openapi-processor-mapping: v12
173173
174174
options:
175175
model-type: record
@@ -234,7 +234,7 @@ Here is a small example that uses object annotation mapping to add the lombok ge
234234

235235
[source,yaml]
236236
----
237-
openapi-processor-mapping: v11
237+
openapi-processor-mapping: v12
238238
239239
options:
240240
package-name: generated
@@ -315,6 +315,14 @@ In case of `google` (or `true`) see also xref:oap::jdk.adoc[JDK 16+].
315315

316316
enables generation of marker interfaces for `oneOf` objects. See xref:processor/one-of-interface.adoc#_marker_interfaces[oneOf marker interfaces].
317317

318+
=== response-interface ([.badge .badge-since]+new with 2025.2+)
319+
320+
**optional** (boolean, `true` or `false`, default is `false`)
321+
322+
enables generation of a marker interface for multiple success (i.e. 2xx) responses with the same content type.
323+
324+
See xref:processor/endpoint-content.adoc[Endpoint content types] for an example.
325+
318326
=== generated-annotation
319327

320328
**optional** (boolean, `true` or `false`, default is `true`)
@@ -365,7 +373,7 @@ The other two can be used if `default` does not work.This is described in more d
365373
*mapping.yaml*
366374
[source,yaml]
367375
----
368-
openapi-processor-mapping: v11
376+
openapi-processor-mapping: v12
369377
370378
options:
371379
enum-type: string

docs/modules/ROOT/pages/processor/endpoint-content.adoc

Lines changed: 166 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
= Endpoint content types
22

3-
A simple path of the OpenAPI description will usually produce a single endpoint method in the target
4-
interface as described in the introduction.
3+
A simple path of the OpenAPI description will usually produce a single endpoint method in the target interface as described in the introduction.
54

6-
OpenAPI allows us to define more complex apis that behave differently based on the request header.
7-
For example the following api definition can return its response in different formats.As json or as
8-
plain text:
5+
OpenAPI allows us to define more complex apis that behave differently based on the request header. For example the following api definition can return its response in different formats. As json or as plain text:
96

107
[source,yaml]
118
----
12-
openapi: 3.0.2
9+
openapi: 3.1.0
1310
info:
1411
title: multiple response content types
1512
version: 1.0.0
@@ -50,11 +47,9 @@ components:
5047
type: string
5148
----
5249

53-
A client request uses the request `Accept` header to tell the api which result content types it can
54-
handle.
50+
A client request uses the request `Accept` header to tell the api which result content types it can handle.
5551

56-
Using a single endpoint method it has to decide which response to create.This leads to some boring
57-
`if/else` code.To avoid this the processor creates one endpoint method for each possible response.
52+
Using a single endpoint method it has to decide which response to create.This leads to some boring `if/else` code. To avoid this the processor creates one endpoint method for each possible response.
5853

5954
== multiple content types
6055

@@ -82,11 +77,9 @@ public interface Api {
8277
}
8378
----
8479

85-
The apis normal response (status '200') can return the result as json or as plain text which leads
86-
to two methods for the same endpoint but with a different `produces` list in the mapping annotation.
80+
The apis normal response (status '200') can return the result as json or as plain text which leads to two methods for the same endpoint but with a different `produces` list in the mapping annotation.
8781

88-
One method when json gets requested and one when plain text gets requested.Spring will take care of
89-
selecting the correct endpoint.
82+
One method when json gets requested and one when plain text gets requested. Spring will take care of selecting the correct endpoint.
9083

9184
[#result_style]
9285
== multiple content types & default content type
@@ -103,13 +96,13 @@ With version *2021.5* it is possible to generate the endpoints with the success
10396

10497
Since it is common practice to handle errors by throwing exceptions (e.g. in combination with the Spring `@ResponseStatus` annotation) the endpoint methods don't need to handle different return types, and it is possible to simply use the type of the success response.
10598

106-
To switch between previous and new behavior there is a new mapping configuration to control the style of the return type named `result-style`.It has two possible values: `success` or `all`.This is currently a global mapping switch.
99+
To switch between previous and new behavior there is a new mapping configuration to control the style of the return type named `result-style`. It has two possible values: `success` or `all`. This is available on all mapping levels (([.badge .badge-since]+new with 2025.2+)).
107100

108-
The default is `success`, i.e. the processor will automatically generate the code using the new behavior.In case the previous behavior is required set the `result-style` to `all`.
101+
The default is `success`, i.e. the processor will automatically generate the code using the new behavior. In case the previous behavior is required, set the `result-style` to `all`.
109102

110103
[source,yaml]
111104
----
112-
openapi-processor-mapping: v8
105+
openapi-processor-mapping: v12
113106
114107
options:
115108
package-name: ...
@@ -121,7 +114,7 @@ map:
121114

122115
**new behavior, since 2021.5**
123116

124-
Example of the new code, using `result-style: success`.This is the default if `result-style` is not set.
117+
Example of the new code, using `result-style: success`. This is the default if `result-style` is not set.
125118

126119
[source,java]
127120
----
@@ -171,6 +164,160 @@ public interface Api {
171164
}
172165
----
173166

167+
== multiple responses with same content type
168+
169+
[.badge .badge-since]+new with 2025.2+
170+
171+
There is a case that was not properly handled before: if an endpoint of the OpenAPI description has multiple success responses with the same content type (e.g. `application/json`) but different response payloads.
172+
173+
The processor did honor only one response status using the _last_ success response.
174+
175+
Here is an example OpenAPI:
176+
177+
[source, yaml]
178+
----
179+
openapi: 3.1.0
180+
info:
181+
title: test multiple success responses
182+
version: 1.0.0
183+
184+
paths:
185+
/foo:
186+
get:
187+
description: endpoint with multiple success responses
188+
responses:
189+
'200':
190+
description: success
191+
content:
192+
application/json:
193+
schema:
194+
$ref: '#/components/schemas/Foo'
195+
'202':
196+
description: another success
197+
content:
198+
application/json:
199+
schema:
200+
$ref: '#/components/schemas/Bar'
201+
202+
components:
203+
schemas:
204+
205+
Foo:
206+
type: object
207+
properties:
208+
foo:
209+
type: string
210+
211+
Bar:
212+
type: object
213+
properties:
214+
bar:
215+
type: string
216+
----
217+
218+
The two result payloads `Foo` and `Bar` are handled by two possible ways now.
219+
220+
Either by using `Object` as return type or by generating a marker interface that's implemented by both payload and using it as the result type.
221+
222+
=== using `Object` as the result type
223+
224+
This is the default. To return either `Foo` or `Bar` from the endpoint method it uses `Object` as the return type.
225+
226+
[source,java]
227+
----
228+
package generated.api;
229+
230+
import annotation.Mapping;
231+
import generated.support.Generated;
232+
233+
@Generated(value = "openapi-processor-core", version = "test")
234+
public interface Api {
235+
236+
@Mapping("/foo")
237+
Object getFooApplicationJson();
238+
239+
}
240+
241+
----
242+
243+
=== using a marker interface as result type
244+
245+
An `Object` return type is obviously not very descriptive. It is impossible to know from the interface which results are possible.
246+
247+
To improve on that situation the processor can generate a marker interface that is more descriptive and helps with navigation in the IDE.
248+
249+
Generation of the marker interface is enabled by adding the `response-interface` option:
250+
251+
[source,yaml]
252+
----
253+
openapi-processor-mapping: v12
254+
255+
options:
256+
package-name: ...
257+
# ...
258+
response-interface: true
259+
----
260+
261+
The generated interface will now look like this:
262+
263+
[source,java]
264+
----
265+
package generated.api;
266+
267+
import annotation.Mapping;
268+
import generated.model.Foo;
269+
import generated.model.GetFooBarAApplicationJsonResponse;
270+
import generated.model.GetFooBarBApplicationJsonResponse;
271+
import generated.support.Generated;
272+
273+
@Generated(value = "openapi-processor-core", version = "test")
274+
public interface Api {
275+
276+
@Mapping("/foo")
277+
GetFooApplicationJsonResponse getFooApplicationJson(); // <1>
278+
279+
}
280+
281+
----
282+
283+
<1> instead of returning `Object` it does return the marker interface type `GetFooApplicationJsonResponse`.
284+
285+
The marker interface is an empty interface and its name is derived from http method, path and content type to create a unique name.
286+
287+
[source,java]
288+
----
289+
package generated.model;
290+
291+
import generated.support.Generated;
292+
293+
@Generated(value = "openapi-processor-core", version = "test")
294+
public interface GetFooApplicationJsonResponse {
295+
}
296+
----
297+
298+
The response payload classes `Foo` and `Bar` will both implement this interface:
299+
300+
[source, java]
301+
----
302+
package generated.model;
303+
304+
import com.fasterxml.jackson.annotation.JsonProperty;
305+
import generated.support.Generated;
306+
307+
@Generated(value = "openapi-processor-core", version = "test")
308+
public class Foo implements GetFooApplicationJsonResponse {
309+
310+
@JsonProperty("foo")
311+
private String foo;
312+
313+
// ...
314+
}
315+
316+
----
317+
318+
If the response type (`Foo` in this case) is used on multiple endpoints with multiple success response status it will implement multiple marker interfaces.
319+
320+
In case one of the success responses is a primitive result (like `String`) the processor will fall back to using `Object` because it can't hide the primitive type behind a marker interface.
174321

175322
== multiple content types, default content type & result wrapper
176323

@@ -206,5 +353,4 @@ public interface Api {
206353
}
207354
----
208355

209-
The response wraps the type by a `ResponseEntity` and to handle the multiple response types the
210-
generic parameter is the *unknown* type.
356+
The response wraps the type by a `ResponseEntity` and to handle the multiple response types the generic parameter is the *unknown* type.

0 commit comments

Comments
 (0)