separate methods for each content-type
30. April 2025
In OpenAPI we can describe api endpoints that receive (request body) or provide (response) payloads in different formats using the content type header.
For example, an endpoint that returns its payload as json or as plain text. Maybe json for processing the result and as plain text to show it in human-readable format.
The OpenAPI could look something like this, (hopefully a bit more meaningful) :
openapi: 3.1.0
info:
title: test multiple response contents
version: 1.0.0
paths:
/foo:
description: success with multiple content-types
get:
responses:
'200':
description: json or plain text result
content:
application/json:
schema:
$ref: '#/components/schemas/Foo'
text/plain:
schema:
type: string
components:
schemas:
Foo:
type: object
properties:
bar:
type: string
What should the interface look like if it gets generated by openapi-processor (or another generator)?
A single method or multiple methods?
single method
If we expect a single method, a union type to return either Foo
or String
would be nice.
@GetMapping(path = "/foo", produces = { "application/json", "text/plain" })
Foo|String getFoo();
Unfortunately, in java we do not have union types and have to fall back to Object
(or a marker interface, which does not work if one result type is a primitive).
Object
is not very helpful because we don’t see what it returns from the method signature.
Another drawback with having a single method is that it would have to conditionally create the Foo
result or the String
result. We can handle a simple if
but we would need some extra noise (i.e., code) that extracts the media type from the request for comparison.
There is probably other stuff we or the generator could invent to handle this.
It works, but this isn’t the most straight forward way. Especially because Spring (or any other web framework) can handle this already by calling different methods based on the content type.
Let’s look at it.
multiple methods
Having two methods, this would be easy to understand:
@GetMapping(path = "/foo", produces = { "application/json" })
Foo getFooApplicationJson();
@GetMapping(path = "/foo", produces = { "text/plain" })
String getFooTextPlain();
Spring (Micronaut or any other web framework) will automatically call the correct method based on the content-type. So we don’t need any code to check that ourselves.
Each method has a meaningful result type, and we are able to see what it returns from the signature. No additional code is needed.
openapi-processor
https://openapi-processor.io does not use the single method version, it always generates the multi-method version.
Here is the full human-readable (interface) code openapi-processor generates from the example OpenAPI description:
package io.openapiprocessor.oap.api;
import io.openapiprocessor.oap.model.Foo;
import io.openapiprocessor.oap.support.Generated;
import org.springframework.web.bind.annotation.GetMapping;
@Generated(value = "openapi-processor-spring", version = "2025.2")
public interface Api {
/**
* @return json or plain text result
*/
@GetMapping(path = "/foo", produces = { "application/json" })
Foo getFooApplicationJson();
/**
* @return json or plain text result
*/
@GetMapping(path = "/foo", produces = { "text/plain" })
String getFooTextPlain();
}
openapi-generator
If you wonder, openapi-generator uses the first solution, at least for java & kotlin. It does not yet support the multi-method solution for Spring (https://github.com/OpenAPITools/openapi-generator/issues/6126).