In this tutorial I will show you how to generate api documentation using MicroProfile OpenAPI and Payara Micro runtime.
Learn more about MicroProfile OpenAPI Specification
Tools You Will Need
Maven 3.3+
Your favorite IDE. I'm using NetBeans
JDK 1.8
Generate Project
We will use Payara Micro Maven archetype to generate our project, run the following command.
$ mvn archetype:generate -DarchetypeGroupId=fish.payara.maven.archetypes -DarchetypeArtifactId=payara-micro-maven-archetype -DarchetypeVersion=1.0.1 -DgroupId=fish.payara.micro -DartifactId=mp-openapi-example -Dversion=1.0-SNAPSHOT -Dpackage=com.kodnito.openapi.rest -Darchetype.interactive=false
Adding Dependencies
Open the project in your favorite IDE and add the following to the pom.xml dependencies section :
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<version>1.0.1</version>
</dependency>
and in plugins section add the following :
<plugin>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>swagger-ui</id>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<skipCache>true</skipCache>
<url>https://github.com/swagger-api/swagger-ui/archive/master.tar.gz</url>
<unpack>true</unpack>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/${project.artifactId}-${project.version}</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/swagger-ui-master/dist</directory>
<filtering>true</filtering>
<excludes>
<exclude>index.html</exclude>
</excludes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Your pom.xml should look like this :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fish.payara.micro</groupId>
<artifactId>mp-openapi-example</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mp-openapi-example</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.javaee>8.0</version.javaee>
<version.payara.micro>5.182</version.payara.micro>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>${version.javaee}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<version>1.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>swagger-ui</id>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<skipCache>true</skipCache>
<url>https://github.com/swagger-api/swagger-ui/archive/master.tar.gz</url>
<unpack>true</unpack>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/${project.artifactId}-${project.version}</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/swagger-ui-master/dist</directory>
<filtering>true</filtering>
<excludes>
<exclude>index.html</exclude>
</excludes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>fish.payara.maven.plugins</groupId>
<artifactId>payara-micro-maven-plugin</artifactId>
<version>1.0.1</version>
<configuration>
<payaraVersion>${version.payara.micro}</payaraVersion>
<deployWar>true</deployWar>
<commandLineOptions>
<option>
<key>--autoBindHttp</key>
</option>
</commandLineOptions>
</configuration>
</plugin>
</plugins>
</build>
</project>
We added MicroProfile OpenAPI dependency and plugin for downloading Swagger UI files for us.
Run the following command to download the dependencies :
$ mvn clean install
inside src/main/webapp/META-INF create the openapi.yaml file and add the following :
openapi: 3.0.0
info:
title: This is my TODO application API Title
description: This is my TODO application description
license:
name: Eclipse Public License - v 1.0
url: https://www.eclipse.org/legal/epl-v10.html
version: 1.0.0
servers:
- url: http://localhost:8080
This is our configuration for our OpenAPI documentation.
Inside src/main/webapp/WEB-INF create glassfish-web.xml and add the following :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<context-root>/</context-root>
</glassfish-web-app>
Here we are changing how we want our application to be deployed.
Resources
Inside src/main/java/com/kodnito/openapi/rest package create the standard ApplicationConfig.java needed by JAX-RS to identify our base endpoint and add the following :
package com.kodnito.openapi.rest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/api")
public class ApplicationConfig extends Application {
}
Now create TodoResource.java file inside src/main/java/com/kodnito/openapi/rest package and add the following :
package com.kodnito.openapi.rest;
import java.util.Properties;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
@RequestScoped
@Path("/todos")
public class TodoResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
@APIResponses(
value = {
@APIResponse(
responseCode = "404",
description = "We could not find the Hello message ",
content = @Content(mediaType = "text/plain"))
,
@APIResponse(
responseCode = "200",
description = "We found the Hello message",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = Properties.class)))})
@Operation(summary = "Outputs Hello Message",
description = "This method outputs Hello message")
public Response sayHello() {
return Response.ok("Hello").build();
}
@GET
@Path("/{id}")
@Operation(summary = "Get Todo by id",
description = "This method gets a single todo by id")
@APIResponse(responseCode = "200", description = "Everything went ok, we found TODO by id")
@APIResponse(responseCode = "404", description = "Todo not found")
public Response getTodoById(@Parameter(description = "Get a specific Todo by id", required = true) @PathParam("id") Long id) {
return Response.ok("").build();
}
}
@APIResponses annotation describes multiple responses
@APIResponse annotation describes a single response
@Operation annotation describes a single operation on a path
@Parameter annotation describes a single operation parameter
Learn more about MicroProfile OpenAPI Specification
Open the index.html file insde src/main/webapp/ and change it to the following :
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://localhost:8080/openapi",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>
Your project directory structure should look like this :
tree . . ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── kodnito │ │ └── openapi │ │ └── rest │ │ ├── ApplicationConfig.java │ │ └── TodoResource.java │ └── webapp │ ├── META-INF │ │ └── openapi.yaml │ ├── WEB-INF │ │ └── glassfish-web.xml │ └── index.html └── test └── java
Now inside your project directory run the following command to start our application :
$ mvn package payara-micro:start
Navigate to http://localhost:8080 and watch your new shiny api documentation :)
Share this: