Eclipse MicroProfile OpenAPI API

The Payara Platform 6.2023.1 provides MicroProfile OpenAPI 3.0

Background

OpenAPI was designed to provide a standard interface for documenting and exposing RESTful APIs. The MicroProfile OpenAPI API provides a set of interfaces and annotations to allow application developers to produce an OpenAPI document from their JAX-RS applications. OpenAPI is somewhat similar to the Swagger API, so many concepts in the API will be familiar.

The complete specification can be found on the Eclipse MicroProfile website.

Breaking changes introduced in MicroProfile OpenAPI 3.0 are listed in the official specification under Incompatible Changes

Version 3.0 of the OpenAPI specification does not define the behaviour of implementations where multiple applications are deployed to the same container. This limitation will be addressed in a later version of the OpenAPI specification. Payara Server allows you to see multiple applications in the OpenAPI document, see multiple applications.

REST Endpoint

MicroProfile OpenAPI specifies that an OpenAPI document should be published at the endpoint /openapi documenting a deployed application. For both Payara Server and Payara Micro, this means that the endpoint can be found on any HTTP port (e.g. 8080) after deploying an application.

The OpenAPI document displayed will always be for the most recently deployed application, except in the special case of disabling the service.

By default, the OpenAPI document is displayed in YAML format, although this can be changed to JSON by changing the Accept header of the request. Alternatively if using a browser, this can also be done by specifying a format query parameter.

For example, http://localhost:8080/openapi?format=json. The valid values are json and yaml.

OpenAPI Configuration Sources

MicroProfile OpenAPI specifies several ways of configuring the data in the produced OpenAPI document. These are all provided by the OpenAPI API artifact:

<dependency>
    <groupId>org.eclipse.microprofile.openapi</groupId>
    <artifactId>microprofile-openapi-api</artifactId>
    <version>{mpOpenAPIVersion}</version>
    <scope>provided</scope>
</dependency>

Configuration Properties

The OpenAPI document generation process can be configured through the Config API. The following are the standard configuration properties as presented by the specification:

Property key Description

mp.openapi.model.reader

Configuration property to specify the fully qualified name of the OASModelReader implementation.

mp.openapi.filter

Configuration property to specify the fully qualified name of the OASFilter implementation.

mp.openapi.scan.disable

Configuration property to disable annotation scanning. Default value is false.

mp.openapi.scan.packages

Configuration property to specify the list of packages to scan. For example, mp.openapi.scan.packages=com.xyz.PackageA,com.xyz.PackageB

mp.openapi.scan.classes

Configuration property to specify the list of classes to scan. For example, mp.openapi.scan.classes=com.xyz.MyClassA,com.xyz.MyClassB

mp.openapi.scan.exclude.packages

Configuration property to specify the list of packages to exclude from scans. For example, mp.openapi.scan.exclude.packages=com.xyz.PackageC,com.xyz.PackageD

mp.openapi.scan.exclude.classes

Configuration property to specify the list of classes to exclude from scans. For example, mp.openapi.scan.exclude.classes=com.xyz.MyClassC,com.xyz.MyClassD

mp.openapi.servers

Configuration property to specify the list of global servers that provide connectivity information. For example, mp.openapi.servers=https://xyz.com/v1,https://abc.com/v1

mp.openapi.servers.path.

Prefix of the configuration property to specify an alternative list of servers to service all operations in a path. For example, mp.openapi.servers.path./airlines/ngs/{id}=https://xyz.io/v1

mp.openapi.servers.operation.

Prefix of the configuration property to specify an alternative list of servers to service an operation. Operations that want to specify an alternative list of servers must define an operationId, a unique string used to identify the operation. For example, mp.openapi.servers.operation.getBooking=https://abc.io/v1

mp.openapi.schema.

Prefix of the configuration property to specify an alternative list of servers to service an operation. Prefix of the configuration property to specify a schema for a specific class, in JSON format. The remainder of the property key must be the fully-qualified class name. The value must be a valid OpenAPI schema object, specified in the JSON format. The use of this property is functionally equivalent to the use of the @Schema annotation on a Java class, but may be used in cases where the application developer does not have access to the source code of a class.

When a name key is provided with a string value, the schema will be added to the schemas collection in the components object of the resulting OpenAPI document using name’s value as the key.

For example, in the case where an application wishes to represent a Java Date object in epoch-style milliseconds, the following configuration can be used (line escapes and indentation added for readability):

mp.openapi.schema.java.util.Date = { \
  "name": "EpochMillis", \
  "type": "number", \
  "format": "int64", \
  "description": "Milliseconds since January 1, 1970, 00:00:00 GMT" \
}

In addition to the standard properties, the following properties have been added as extensions within the Payara Platform:

Property key

Description

mp.openapi.scan.lib

Configuration property that allows the server to scan packaged JAR files inside the WAR’s library directory (WEB-INF/lib). Default value is false.

OASModelReader

org.eclipse.microprofile.openapi.OASModelReader

The OASModelReader interface can be implemented by an application developer. It must then be declared as a Config API variable in the form:

mp.openapi.model.reader=fish.payara.examples.OASModelReaderImpl

This class will be called at the beginning of the OpenAPI document generation, and will create the initial OpenAPI document.

OASFilter

org.eclipse.microprofile.openapi.OASFilter

The OASFilter interface can be implemented by an application developer. It must then be declared as a Config API variable in the form:

mp.openapi.filter=fish.payara.examples.OASFilterImpl

Each method in the implementation will be called on every appropriate element in the OpenAPI model. For example, the method filterPathItem(PathItem pathItem) will be called for every PathItem in the document. This class is called last, before the document is published.

Static Document

The MicroProfile OpenAPI supports using a static OpenAPI document to build from. This static file can be placed in either META-INF directory in a WAR file. Most often, this means putting the file in src/main/resources/META-INF.

The following file names are allowed for this file. The file given must also be in the specified format.

File Format

Allowed File Names

yaml

openapi.yaml openapi.yml

json

openapi.json

Annotations

The MicroProfile OpenAPI API provides many annotations to use to augment the OpenAPI document. These are detailed in the OpenAPI Specification. These annotations are applied before the OASFilter.

Example

The following code could be used to give the corresponding operation an ID of "hello world".

import org.eclipse.microprofile.openapi.annotations.Operation;

@Path("/app")
public class AppResource{
    @GET
    @Operation(operationId = "hello world")
    public String helloWorld() {
        return "Hello World!";
    }
}
Here’s an example of how the OpenAPI document of a sample application would look like
openapi: 3.0.0
info:
  title: A Test Application
  version: "1.0"
servers:
- url: http://localhost:8080/openapi-example-1.0
  description: Default Server.
- url: https://localhost:8181/openapi-example-1.0
  description: Default Server.
paths:
  /api/hello:
    get:
      operationId: hello-world
      responses:
        default:
          content:
            text/plain:
              schema:
                type: string
          description: Default Response.
      deprecated: false
endpoints:
  /openapi-example-1.0:
  - /api/hello
components: {}

Deployed Endpoints

When more than one application is deployed, a merge is done in the OpenAPI document. The resulting document will contain all application and path definitions present. To improve the its readability, an endpoints attribute which lists all deployed endpoints grouped by their application context roots has been added to the document.

The endpoints attribute is an proprietary Payara Platform extension and it’s not portable.
The following example shows an OpenAPI document generated when 2 different applications are deployed
openapi: 3.0.0
info:
  title: Deployed Resources
  version: 1.0.0
servers:
- url: http://localhost:8080/ClusteredSingleton
  description: Default Server.
- url: https://localhost:8181/ClusteredSingleton
  description: Default Server.
- url: http://localhost:8080/SimpleWAR
  description: Default Server.
- url: https://localhost:8181/SimpleWAR
  description: Default Server.
paths:
  /resources/javaee8:
    get:
      operationId: ping
      responses:
        default:
          content:
            '*/*':
              schema:
                type: object
          description: Default Response.
  /resources/randomNumberGen:
    get:
      operationId: randomNumberGen
      responses:
        default:
          content:
            '*/*':
              schema:
                type: integer
          description: Default Response.
  /rest/request:
    get:
      operationId: getXml
      responses:
        default:
          content:
            text/plain:
              schema:
                type: string
          description: Default Response.
    put:
      operationId: putXml
      requestBody:
        content:
          application/xml:
            schema:
              type: string
      responses:
        default:
          content:
            '*/*':
              schema:
                type: object
          description: Default Response.
endpoints:
  /ClusteredSingleton:
  - /resources/javaee8
  - /resources/randomNumberGen
  /SimpleWAR:
  - /rest/request
components: {}

OpenAPI Configuration

On Payara Server, MicroProfile OpenAPI settings can be configured by using the Admin Console or Asadmin CLI commands.

Using the Admin Console

To configure the OpenAPI in the Admin Console, go to Configuration → [instance-configuration (like server-config)] → MicroProfile → OpenAPI:

Set OpenAPI Configuration

Using Asadmin Commands

Use the following commands to configure the settings of the MicroProfile OpenAPI service:

Security Configuration

By default, the OpenAPI endpoint binds to the root context application which is the default-web-module (also known as docroot) system application and the default-web-module application, which is secured under the default realm (file) of the server.

If a user application is deployed in the empty context-root, then the security configuration of this application will be shared by the OpenAPI endpoint, so exert extreme caution when making these changes.

Upgrading from MicroProfile 3.x to 4.x

MicroProfile 4.0 brings with it a number of changes to MicroProfile OpenAPI, among these changes are some which break previous behaviour. The breaking changes are primarily to do with the removal of a number of methods previously marked as deprecated from the API, and only affect the use of OpenAPI programmatically (there are no breaking changes pertaining to the use of the annotations).

  • Scopes interface removed - Use Map<String, ServerVariable>.

  • ServerVariables interface removed - Use Map<String, ServerVariable>.

  • The following interfaces no longer extend Map - Ensure you are not using any of the methods or functionality gained from the Map class:

    • APIResponses

      • get(Object key) - Use getAPIResponse(String).

      • containsKey(Object key) - Use hasAPIResponse(String).

      • put(String key, PathItem value) - Use addAPIResponse(String, APIResponse).

      • putAll(Map<? extends String, ? extends APIResponse> m) - Use setAPIResponses(Map).

      • remove(Object key) - Use removeAPIResponse(String).

    • Callback

      • get(Object key) - Use getPathItem(String).

      • containsKey(Object key) - Use hasPathItem(String).

      • put(String key, PathItem value) - Use addPathItem(String, PathItem).

      • putAll(Map<? extends String, ? extends PathItem> m) - Use setPathItems(Map).

      • remove(Object key) - Use removePathItem(String).

    • Content

      • get(Object key) - Use getMediaType(String).

      • containsKey(Object key) - Use hasMediaType(String).

      • put(String key, MediaType value) - Use addMediaType(String, MediaType).

      • putAll(Map<? extends String, ? extends MediaType> m) - Use setMediaTypes(Map).

      • remove(Object key) - Use removeMediaType(String).

    • Path

      • get(Object key) - Use getPathItem(String).

      • containsKey(Object key) - Use hasPathItem(String).

      • put(String key, PathItem value) - Use addPathItem(String, PathItem).

      • putAll(Map<? extends String, ? extends PathItem> m) - Use setPathItems(Map).

      • remove(Object key) - Use removePathItem(String).

    • SecurityRequirement

      • get(Object key) - Use getScheme(String).

      • containsKey(Object key) - Use hasScheme(String).

      • put(String key, List<String> value) - Use addScheme(String, List<String>).

      • putAll(Map<? extends String, ? extends List<String> m) - Use setSchemes(Map).

      • remove(Object key) - Use removeScheme(String).

  • A number of methods have been removed from model interfaces, in addition to those above:

    • OASFactory

      • createScopes - use Map<String, String>.

      • createServerVariables - use Map<String, ServerVariable>.

    • OAuthFlow

      • setScopes(Scopes scopes) - Use setScopes(Map).

      • scopes(Scopes scopes) - Use scopes(Map).

    • OpenAPI

      • path(String name, PathItem path) - use Paths#addPathItem(String, PathItem) on OpenAPI#getPaths

    • PathItem

      • readOperations - use Map#values() on PathItem#getOperations().

      • readOperationsMap - use getOperations().

    • Schema

      • getAdditionalProperties - use getAdditionalPropertiesSchema() or getAdditionalPropertiesBoolean().

      • setAdditionalProperties(Schema additionalProperties) - use setAdditionalPropertiesSchema(Schema).

      • setAdditionalProperties(Boolean additionalProperties) - use setAdditionalPropertiesBoolean(Boolean).

      • additionalProperties(Schema additionalProperties) - use additionalPropertiesSchema(Schema).

      • additionalProperties(Boolean additionalProperties) - use additionalPropertiesBoolean(Boolean).

    • Server

      • setVariables(ServerVariables variables) - Use setVariables(Map).

      • variables(ServerVariables variables) - Use variables(Map).