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).

summary

This article described that openapi-processor does generate a method for each response content-type of an endpoint and lets the framework decide which one to call. This produces less code we can handle the different content-types without conditional logic.