Quarkus - OpenAPI Generator - Server with Apicurio

This documentation helps you to use Quarkus OpenAPI Generator Server with the Apicurio code generator. To see how to use with OpenAPITools, please see the OpenAPITools documentation.

Getting Started

Add the following dependency to your project’s pom.xml file:

<dependency>
  <groupId>io.quarkiverse.openapi.generator</groupId>
  <artifactId>quarkus-openapi-generator-server</artifactId>
  <version>3.0.0-SNAPSHOT</version>
</dependency>

By default, the generated resources are annotated with Microprofile OpenAPI annotations, add the io.quarkus:quarkus-smallrye-openapi dependency to your project’s pom.xml file:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>

Note that since this extension has not been yet released, you’ll need a local build of the dependency.

You will also need to add or update the quarkus-maven-plugin configuration with the following:

You probably already have this configuration if you created your application with Code Quarkus. That said, double-check your configuration not to add another plugin entry.
<plugin>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-maven-plugin</artifactId>
  <extensions>true</extensions>
  <executions>
    <execution>
      <goals>
        <goal>build</goal>
        <goal>generate-code</goal>
        <goal>generate-code-tests</goal>
      </goals>
    </execution>
  </executions>
</plugin>

To use the Apicurio (used by default) code generator, you need to configure your application.properties as follow:

quarkus.openapi.generator.server.use=apicurio

Now, create the directory openapi under your src/main/resources path and add the OpenAPI spec files there. We support JSON, YAML and YML extensions. You have to define the specification used for code generation with the following property:

quarkus.openapi.generator.server.spec=petstore-openapi.json

If you want to change the directory where OpenAPI files must be found, use the property quarkus.openapi.input-base-dir. IMPORTANT: it is relative to the project base directory. For example, if you have a project called MyJavaProject and decide to place them in MyJavaProject/openapi-definitions, use the following property:

quarkus.openapi.generator.server.input-base-dir=openapi-definitions

If a base package name is not provided, it will be used the default io.apicurio.api. You can customize it with the following property:

quarkus.openapi.generator.server.base-package=io.petstore

By default, the extension generates non-reactive code. If you would like to change it, you can do it as follows:

quarkus.openapi.generator.server.use-reactive=true

Run mvn compile to generate your classes in target/generated-sources/jaxrs path:

- io.petstore
  - beans
    - Address.java
    - ApiResponse.java
    - Category.java
    - Customer.java
    - Order.java
    - Pet.java
    - Tag.java
    - User.java
  - PetResource.java
  - StoreResource.java
  - UserResource.java

You can reference the generated code in your project, for example:

package io.petstore;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.petstore.beans.ApiResponse;
import io.petstore.beans.Pet;

public class PetStoreImpl implements PetResource {

    private static final Map<Long, Pet> PETS = new HashMap<>();

    @Override
    public Pet updatePet(Pet data) {
        return PETS.put(data.getId(), data);
    }

    @Override
    public Pet addPet(Pet data) {
        return PETS.put(data.getId(), data);
    }

    @Override
    public List<Pet> findPetsByStatus(String status) {
        return null;
    }

    @Override
    public List<Pet> findPetsByTags(List<String> tags) {
        return null;
    }

    @Override
    public Pet getPetById(long petId) {
        return PETS.get(petId);
    }

    @Override
    public void updatePetWithForm(long petId, String name, String status) {

    }

    @Override
    public void deletePet(String apiKey, long petId) {
        PETS.remove(petId);
    }

    @Override
    public ApiResponse uploadFile(long petId, String additionalMetadata, InputStream data) {
        return null;
    }
}

See the integration-tests module for more information of how to use this extension. Please be advised that the extension is on experimental, early development stage.

Multi-file and multiple specifications

Apicurio can generate from entry specs that use relative $ref values across multiple YAML or JSON files. Keep the referenced files under the same input base directory as the entry document and configure the entry spec normally:

quarkus.openapi.generator.server.use=apicurio
quarkus.openapi.generator.server.input-base-dir=src/main/resources/openapi
quarkus.openapi.generator.server.spec=module1.yaml

You can also generate multiple server stubs in one build:

quarkus.openapi.generator.server.use=apicurio
quarkus.openapi.generator.server.spec.petstore_openapi_json.base-package=org.acme.api.petstore
quarkus.openapi.generator.server.spec.simple_server_yaml.base-package=org.acme.api.animals

Any OpenAPI specification files in the input base directory that are not explicitly configured under server.spec.<id>.* are automatically discovered and generated using default values (e.g., base-package=org.acme, use-builders=true). To exclude files from auto-discovery (such as shared reference files like common-spec.yaml), use the quarkus.openapi.generator.server.exclude property.

As with OpenAPITools, the identifier may also be an alias when you set quarkus.openapi.generator.server.spec.<id>.spec=<file> and, optionally, quarkus.openapi.generator.server.spec.<id>.input-base-dir=<dir>.

Codegen Extensions

Apicurio Codegen Extensions use OpenAPI specification extensions to allow customization of the generated source code based on your API contract.

x-codegen

The x-codegen extension can be defined at the root level of the OpenAPI document.

It is applied globally and allows you to customize the generated bean classes by: - Adding annotations to all generated beans. - Controlling date/time formatting. - Configuring the application context root.

x-codegen.bean-annotations

Adding annotations to generated bean classes:

{
  "x-codegen": {
    "bean-annotations": [
      "@lombok.ToString", // (1)
      {
        "annotation": "@lombok.EqualsAndHashCode", // (2)
        "excludeEnums": true
      }
    ]
  }
}
  1. Adds the @lombok.ToString annotation to all generated bean classes.

  2. Adds the @lombok.EqualsAndHashCode annotation to all generated bean classes, except for Java enums (when excludeEnums is set to true).

x-codegen.contextRoot

Additionally, you can configure the application context root using the x-codegen.contextRoot property.

This property defines a base path that will be automatically prefixed to all generated JAX-RS resource classes.

For example, if you set the context root to /apis/studio/v1, all generated resource paths will include this prefix.

{
  "x-codegen": {
    "contextRoot": "/apis/studio/v1",
    "bean-annotations": []
  }
}

Corresponding JAX-RS code:

@Path("/apis/studio/v1/users")
public class UserResource {}
You can use the x-codegen-contextRoot property to apply a context root prefix to a specific JAX-RS resource instead of using the global one.

x-codegen.suppress-date-time-formatting

By default, Apicurio Codegen generates properties of type string with the format date-time as shown below:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
@JsonProperty("shipDate")
private Date shipDate;

If you want to disable this behavior, you can use the x-codegen.suppress-date-time-formatting property to remove the @JsonFormat annotation from generated fields.

{
  "x-codegen": {
    "suppress-date-time-formatting": true
  }
}

The following extensions modify the behavior of the code generation in specific parts of the OpenAPI document.

x-codegen-package

The x-codegen-package extension allows you to define the package where a generated class should be placed. This extension is applicable to components of type schema.

Where to use components.schemas.<SchemaName>.x-codegen-package
Example usage:
{
  "components": {
    "schemas": {
      "ArtifactState": {
        "description": "Describes the state of an artifact or artifact version. The following states\nare possible:\n\n* ENABLED\n* DISABLED\n* DEPRECATED\n",
        "enum": [
          "ENABLED",
          "DISABLED",
          "DEPRECATED"
        ],
        "type": "string",
        "x-codegen-package": "io.apicurio.registry.types"
      }
    }
  }
}

This configuration generates the ArtifactState class in the package io.apicurio.registry.types:

package io.apicurio.registry.types;

public enum ArtifactState {
    ENABLED, DISABLED, DEPRECATED
}

x-codegen-async

The x-codegen-async extension allows you to define whether a generated method should return asynchronously (e.g., wrapped in CompletionStage). This extension can be used on any HTTP operation (get, post, etc.).

Where to use paths.<path>.<operation>.x-codegen-async
Example usage:
"/cart/ids": {
  "get": {
    "summary": "Get a cart by ID",
    "operationId": "getCartByID",
    "description": "Get a cart resource by ID",
    "tags": [
      "Cart"
    ],
    "x-codegen-async": true
  }
}

This configuration generates the following asynchronous JAX-RS method:

@Path("/cart/ids")
@GET
@Produces("application/json")
CompletionStage<String> getCartByID();

x-codegen-returnType

The x-codegen-returnType extension allows you to explicitly define the return type of a generated method, overriding the type inferred from the schema. This is useful for advanced use cases, such as returning reactive types, server-sent events (SSE), or custom wrappers.

Where to use paths.<path>.<operation>.responses.<statusCode>.content.<mediaType>.x-codegen-returnType
Example usage:
"responses": {
  "200": {
    "description": "A continuous stream of cart IDs",
    "content": {
      "text/event-stream": {
        "schema": {
          "type": "string"
        },
        "x-codegen-returnType": "io.smallrye.mutiny.Multi<String>",
      }
    }
  }
}

This configuration generates the following method using the specified return type (Multi<String> from Mutiny):

import io.smallrye.mutiny.Multi;

/* omitted for simplicity */
@Produces("text/event-stream")
Multi<String> getCartIds();

x-codegen-returnType must be placed at the media type object level (sibling of schema), not inside the schema object.

Configuring x-codegen-returnType via application.properties

Instead of editing the OpenAPI specification directly, you can configure the return type for an operation using the operation-ids map in application.properties. The extension value will be automatically injected into the spec before code generation.

Property quarkus.openapi.generator.server.operation-ids."<operationId>".return-type
Example application.properties:
quarkus.openapi.generator.server.operation-ids."getCartIds".return-type=io.smallrye.mutiny.Multi<String>

This is equivalent to manually placing x-codegen-returnType on every response media type of the getCartIds operation in the spec.

This approach keeps your OpenAPI specification clean and vendor-extension free. The injection happens at build time only.

x-codegen-annotations

The x-codegen-annotations extension allows you to add annotations to the generated code. This extension is supported in two specific contexts:

Where to use - components.schemas.<SchemaName>.x-codegen-annotations (adds annotations at the class level)
- paths.<path>.<operation>.parameters[].x-codegen-annotations (adds annotations to method parameters)
Example on a schema (class-level annotation):
"MyQuarkusBean": {
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "description": {
      "type": "string"
    }
  },
  "x-codegen-annotations": [
    "io.quarkus.runtime.annotations.RegisterForReflection"
  ]
}

This results in the following class-level annotation:

@RegisterForReflection
public class MyQuarkusBean {
    private String name;
    private String description;
}
Example on a method parameter:
"parameters": [
  {
    "name": "beerId",
    "in": "path",
    "required": true,
    "description": "Unique ID of a beer.",
    "schema": {
      "type": "integer",
      "format": "int32"
    },
    "x-codegen-annotations": [
      "@jakarta.validation.constraints.Positive(message = \"The beerId must be a natural number!\")"
    ]
  }
]

This adds the annotation to the generated method parameter:

public Response deleteBeer(
    @Positive(message = "The beerId must be a natural number!") int beerId
);

x-codegen-contextRoot

The x-codegen-contextRoot extension allows you to define a base path (context root) that is prepended to all generated endpoint paths.

Where to use x-codegen-contextRoot should be placed at the root level of the OpenAPI document (next to info, paths, etc.)
Example usage:
{
  "openapi": "3.0.2",
  "info": {
    "title": "Context Root Sample API",
    "version": "1.0.0"
  },
  "paths": {
    "/widgets": {
      "get": {
        "operationId": "getWidgets",
        "summary": "Get widgets",
        "responses": {
          "200": {
            "description": "Returns the list of widgets.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "x-codegen-contextRoot": "/api/v3"
}

This configuration prepends /api/v3 to all paths, resulting in:

@Path("/api/v3/widgets")
public interface WidgetsResource {

    @Operation(summary = "Get widgets", operationId = "getWidgets")
    @GET
    @Produces("application/json")
    List<String> getWidgets();
}

x-codegen-formatPattern

The x-codegen-formatPattern extension allows you to customize the date/time format pattern used for serialization and deserialization of date fields.

Where to use components.schemas.<SchemaName>.properties.<propertyName>.x-codegen-formatPattern
Example usage:
"VersionMetaData": {
  "type": "object",
  "properties": {
    "createdOn": {
      "type": "string",
      "format": "date-time",
      "x-codegen-formatPattern": "yyyy-MM-dd'T'HH:mm:ss"
    }
  }
}

This generates the following annotated field:

@JsonFormat(
    shape = Shape.STRING,
    pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'",
    timezone = "UTC"
)
@JsonProperty("createdOn")
private Date createdOn;

x-codegen-inline / x-codegen-inlined

The x-codegen-inline (or x-codegen-inlined) extension indicates that a schema should be inlined directly into the property where it is referenced, rather than generating a separate Java class.

This is useful for simplifying the generated model when the referenced schema is small or generic, such as maps or simple value types.

Where to use components.schemas.<SchemaName>.x-codegen-inline
components.schemas.<SchemaName>.x-codegen-inlined

Both x-codegen-inline and x-codegen-inlined are aliases and behave the same way.

Example usage:
"MyMap": {
  "type": "object",
  "additionalProperties": {
    "type": "string"
  },
  "x-codegen-type": "StringMap",
  "x-codegen-inline": true
}

When another schema references MyMap, it will be inlined as Map<String, String> instead of generating a separate MyMap Java class.

Example result (inlined):
@JsonProperty("mymap")
private Map<String, String> mymap;

If the extension was not present, the field would instead be generated with a custom type:

@JsonProperty("mymap")
private MyMap mymap;

x-codegen-type

The x-codegen-type extension is used to override the type of a generated bean class. It is especially important when combined with x-codegen-inline.

Why use x-codegen-type?

When using x-codegen-inline: true, the code generator will not generate a Java class for the given schema. However, in order to correctly reference the type in generated code, it still needs to know the Java type to use in place of the schema.

Without x-codegen-type, the code generator won’t know what type to substitute, and this will result in an error during code generation.

Example

"MyMap": {
  "type": "object",
  "additionalProperties": {
    "type": "string"
  },
  "x-codegen-type": "StringMap",
  "x-codegen-inline": true
}

In this example, instead of generating a class called MyMap, the generator will use Map<String, String> directly wherever this schema is referenced.

If you want the schema to be generated as Map<String, Object> (instead of Map<String, String>), set its x-codegen-type to StringObjectMap.

Invalid Example (Will Fail)

"MyMap": {
  "type": "object",
  "additionalProperties": {
    "type": "string"
  },
  "x-codegen-inline": true
}

Since x-codegen-type is missing, the generator has no information about the Java type to use and will throw an error.

x-codegen-extendsClass

This extension allows the generated Java class to extend a custom base class.

Usage

You must define the fully qualified class name in the OpenAPI schema using the x-codegen-extendsClass property.

Example OpenAPI Specification

{
  "openapi": "3.0.2",
  "info": {
    "title": "Schema Extends API",
    "version": "1.0.0"
  },
  "paths": {},
  "components": {
    "schemas": {
      "MySchema": {
        "type": "object",
        "x-codegen-type": "bean",
        "x-codegen-extendsClass": "io.quarkus.openapi.generator.server.AbstractSchema",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      }
    }
  }
}

Example Base Class

package io.quarkus.openapi.generator.server;

public class AbstractSchema {
}

Resulting Generated Class

public class MySchema extends AbstractSchema {
    /* omitted for simplicity */
}

Multipart Form-Data Support

When an OpenAPI operation defines a multipart/form-data request body, the Apicurio code generator produces a properly typed JAX-RS method with a @MultipartForm annotated parameter, rather than falling back to a generic InputStream.

For example, given the following OpenAPI definition:

paths:
  /upload:
    post:
      operationId: uploadFile
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                description:
                  type: string
      responses:
        "200":
          description: Upload successful

The generator produces:

@POST
@Path("/upload")
@Consumes("multipart/form-data")
public Response uploadFile(@MultipartForm UploadFileMultipartBody data);

Where UploadFileMultipartBody is a generated class with each multipart field annotated with @FormParam and an appropriate @PartType.

This feature requires apicurio-codegen version 1.2.9.Final or later.

Configuration Properties

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

This property is deprecated: Use quarkus.openapi.generator.server.<tool>.spec instead.

The OpenAPI specification filename.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SPEC

string

This property is deprecated: Use quarkus.openapi.generator.server.<tool>.input-base-dir instead.

The input base dir where the OpenAPI specification is.

Environment variable: QUARKUS_OPENAPI_GENERATOR_INPUT_BASE_DIR

string

This property is deprecated: Use quarkus.openapi.generator.server.<tool>.use-reactive instead.

Whether it must generate with reactive code.

Environment variable: QUARKUS_OPENAPI_GENERATOR_REACTIVE

boolean

This property is deprecated: quarkus.openapi.generator.server.<tool>.use-builders instead.

Whether it must generate builders for properties.

Environment variable: QUARKUS_OPENAPI_GENERATOR_BUILDERS

boolean

This property is deprecated: Use quarkus.openapi.generator.server.<tool>.base-package instead.

The base package to be used to generated sources.

Environment variable: QUARKUS_OPENAPI_GENERATOR_BASE_PACKAGE

string

This property is deprecated: Use quarkus.openapi.generator.server.<tool>.use-bean-validation instead.

Whether it must generate resources and beans using bean validation (JSR-303).

Environment variable: QUARKUS_OPENAPI_GENERATOR_USE_BEAN_VALIDATION

boolean

The generator to be used for generating the server code.

Possible values are: apicurio or openapitools.

By default, is apicurio.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_USE

string

apicurio

The OpenAPI specification filename.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_SPEC

string

The input base dir where the OpenAPI specification is.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_INPUT_BASE_DIR

string

src/main/resources/openapi

Whether it must generate with reactive code.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_USE_REACTIVE

boolean

false

Whether it must generate builders for properties.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_USE_BUILDER

boolean

false

The base package to be used to generated sources.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_BASE_PACKAGE

string

org.acme

Whether it must generate resources and beans using bean validation (JSR-303).

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_USE_BEAN_VALIDATION

boolean

false

Whether the generated server methods should use org.jboss.resteasy.reactive.RestResponse<T> as the return type for single-response endpoints. When enabled, methods return RestResponse<Model> (or Uni<RestResponse<Model>> in reactive mode), allowing implementors to control the HTTP response status code (e.g. 201 Created). Streaming endpoints are out of scope for this flag. This property only applies when using the openapitools code generator (i.e. when quarkus.openapi.generator.server.use is set to openapitools). By default this is false, preserving backward-compatible return types.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_USE_REST_RESPONSE

boolean

false

Whether to skip generation when the persisted fingerprint of the OpenAPI specification and relevant generation configuration matches the previous run.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_SKIP_IF_UNCHANGED

boolean

false

List of OpenAPI file names to include for code generation. When set, only the listed files are processed by the auto-discovery mechanism.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_INCLUDE

list of string

List of OpenAPI file names to exclude from code generation. When set, the listed files are skipped by the auto-discovery mechanism. This is useful for excluding shared reference files (e.g., common-spec.yaml) that are not standalone specifications.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_EXCLUDE

list of string

The name of the method parameter that should be used to return the response from the operation.

Environment variable: QUARKUS_OPENAPI_GENERATOR_SERVER_OPERATION_IDS__OPERATION_IDS__RETURN_TYPE

string

required