API documentation with OpenAPI

MicroProfile OpenAPI helps you to generate structured documentation from your Jakarta RESTful Services or JAX-RS applications. This documentation helps other microservices and developers to understand and communicate with your application.

Other developers need relevant information to build an application that communicates with the REST API of your application. MicroProfile OpenAPI facilitates this communication by generating human and machine-readable documentation on a simple interface that doesn’t require access to the source code.

You can implement MicroProfile OpenAPI for Open Liberty by enabling the MicroProfile OpenAPI feature. When this feature is enabled, you can view the OpenAPI document in a browser by using the /openapi endpoint. For example, if your browser is on the same machine where your server is running, you can view the raw OpenAPI document at the http://localhost:9080/openapi URL or view the OpenAPI document in a user interface at the http://localhost:9080/openapi/ui URL.

To explore how to document and filter RESTful APIs from code or static files by using Open Liberty and MicroProfile OpenAPI, see the Documenting RESTful APIs guide.

The two main approaches to generate an OpenAPI document are the code-first approach and the design-first approach. In the code-first approach, you can generate documentation of the REST API from the source code. The reference document that is produced lists all the API endpoints with descriptions of how to use them. Alternatively, in the design-first approach, you can include a pre-generated OpenAPI document that was written separately from the code. The JAX-RS framework handles basic API generation for JAX-RS annotations and generates a skeleton OpenAPI treemap. You can use this treemap as a starting point and augment it with annotations and code to produce a complete OpenAPI document. Additionally, you can use this manually created documentation to generate stubs, or testable versions of code modules, such as client libraries for the API.

The code-first approach

In the code-first approach, you can initially generate basic API documentation of the REST API from annotations that are specified in the source code. Then, you can augment the existing annotations with OpenAPI annotations, which are processed to generate the documentation. Adding annotations takes less work than manually defining the OpenAPI document, and gives a useful explanation of the different parts of the API.

In the following example, the OpenAPI annotations @APIResponses, @Operation, and @Parameter are added to the purchaseCar() JAX-RS method.

@PUT
 @Path("/buy/{registration}")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.TEXT_PLAIN)
 @APIResponses(
         value = {
             @APIResponse(
                 responseCode = "404",
                 description = "The requested car could not be found at the dealership, and could not be purchased.",
                 content = @Content(mediaType = "text/plain")),
             @APIResponse(
                 responseCode = "200",
                 description = "The requested car was successfully purchased.",
                 content = @Content(mediaType = "application/json"))})
     @Operation(
         summary = "Purchases the specified car from the dealership, and adds the car to your garage.",
         description = "Retrieves the car with the specified registration from the dealership if it exists, and
                        adds this to the caller's garage. The boolean response represents the state of the internal operation.")
 public Response purchaseCar(
    @Parameter(
              description = "The registration of the car to be added to the inventory.",
              required = true,
              example = "NX15 9012",
              schema = @Schema(type = SchemaType.STRING))
    @PathParam("registration") String registration) {
  boolean success = manager.purchaseCar(registration);
     if (!success) {
         return Response.status(Response.Status.NOT_FOUND)
                        .entity("{ \"error\" : "
                                + "\"The car with registration " + registration
                                + " could not be added to the inventory\" }")
                        .build();
     }
     return Response.ok(success).build();
 }

The default format of the generated document is YAML, but documents can also be provided in JSON format. The following OpenAPI document is generated in YAML format from the OpenAPI annotations in the previous example.

/my-garage/buy/{registration}:
   put:
     summary: "Purchases the specified car from the dealership, and adds the car\
       \ to your garage."
     description: "Retrieves the car with the specified registration from the dealership\
       \ if it exists, and adds this to the caller's garage. The boolean response\
       \ represents the state of the internal operation."
     parameters:
     - name: registration
       in: path
       description: The registration of the car to be added to the inventory.
       required: true
       schema:
         type: string
       example: NX15 9012
     responses:
       "404":
         description: "The requested car could not be found at the dealership, and\
           \ could not be purchased."
         content:
           text/plain: {}
       "200":
         description: The requested car was successfully purchased.
         content:
           application/json: {}

The information that is provided through the OpenAPI annotations augments the basic API documentation that is generated by the JAX-RS framework.

For more information, see the MicroProfile OpenAPI Javadoc for the available annotations.

The design-first approach

An alternative approach is to design the REST API in an editor, such as the Swagger editor, before you write any code. With this approach, you can spot and rectify any issues in the design before it is implemented. In large companies, subject matter experts review the API to ensure it’s consistent and usable. This API design then forms a contract and must be implemented as agreed.

You can write this API design in YAML or JSON format and place it in the META-INF directory of your application. Optionally, you can create stubs for the API code. The code-first and design-first approaches are not mutually exclusive. You can augment manually created API documents by adding annotations to the code as you would in a code-first approach.

For more information, see Using pregenerated OpenAPI documents.

Multiple application and multi-module application support with MicroProfile OpenAPI

By default, OpenAPI documentation is generated for only the first web module of the first application that is deployed on the server. The MicroProfile OpenAPI feature, version 2.0 and later, provides configuration properties to select which applications and web modules OpenAPI documentation is generated for. If more than one web module or application is specified, an OpenAPI document is generated for each module or application and then they are merged to create a single OpenAPI document. A property is also provided to set the info section of the final merged OpenAPI document.

For example, to include all the applications in your deployment in a single merged OpenAPI document, you can define the following MicroProfile Config property as a variable in your server.xml file.

<variable name="mp.openapi.extensions.liberty.merged.include" value="all"/>

The following table lists MicroProfile Config properties that can be specified to configure which modules or applications are included in the generated OpenAPI documentation. These properties are available when you enable the MicroProfile OpenAPI feature, version 2.0 and later. Alternatively, you can specify the MicroProfile convenience feature, version 4.0 or later, which automatically enables the full set of MicroProfile features. For configuration examples, see the MicroProfile OpenAPI feature.

Configuration properties for multiple application and multi-module application support
Property nameDescriptionDefault valueValid values

mp.openapi.extensions.liberty.merged.include

This property specifies which modules or applications are included in the generated OpenAPI documentation.

first

  • all
    This value includes all modules and applications in a deployment.

  • first
    This value includes only the first web module of the first application deployed.

  • A comma-separated list of application_name or application_name/module_name includes the named applications and modules.

mp.openapi.extensions.liberty.merged.exclude

This property overrides the mp.openapi.extensions.liberty.merged.include property to specify which applications or web modules are excluded from the generated OpenAPI documentation.

none

  • none
    This value excludes no applications or web modules.

  • A comma-separated list of application_name or application_name/module_name excludes the named applications and modules.

mp.openapi.extensions.liberty.merged.info

This property sets the info section of the final Open API document. If it is set, the info section in the final OpenAPI document is replaced with the value of the property. This replacement is made after any merging is completed.

N/A

The value must be a valid OpenAPI info section in JSON format.

Resolution of OpenAPI document merging conflicts

When OpenAPI documentation from multiple modules is merged into a single document, Open Liberty applies the following rules to resolve potential conflicts between the OpenAPI documents that are being merged.

  • If all server URLs end with the context root, the context root is removed from each server URL and added as a prefix to each path. If no servers exist in a document, the context root is added as a prefix to each path. If the same path is then declared in more than one document, a warning is logged and all but one of the clashing documents is excluded from the merged documentation.

  • If the same extension name is declared with different values at the top level of more than one document, a warning is logged. All but one of the clashing documents are excluded from the merged documentation.

  • If the top-level servers section is not identical across all documents, each server is removed from the top level and copied under the paths that it applies to.

  • Component names are made unique by adding a number to the end of them where necessary. References to the component name are updated.

  • Operation IDs are made unique by adding a number to the end of them where necessary. References to the operation ID are updated.

  • If the info section is not identical across all documents, it is replaced by a standard info section that says that the documentation from several modules was merged.

  • If the top-level security section is not the same across all documents, the security requirements are copied under each operation that they apply to.

  • If the externalDocs section is not the same across all documents, it is removed from the final document.