1. OpenAPI
This module helps automating the generation of API documentation using Jooby projects. jooby-openapi works by examining an application at build time to infer API semantics based on byte code and optional annotations.
Automatically generates documentation in JSON/YAML format APIs. This documentation can be completed by comments using swagger-api annotations.
This library supports:
-
OpenAPI 3 (json and yaml)
-
Swagger UI (Optional)
-
Redoc (Optional)
1.1. Configuration
<properties>
<application.class>myapp.App</application.class>
</properties>
...
<plugins>
...
<plugin>
<groupId>io.jooby</groupId>
<artifactId>jooby-maven-plugin</artifactId>
<version>3.5.3</version>
<executions>
<execution>
<goals>
<goal>openapi</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
The default phase of the plugin execution is |
1.2. Usage
To learn how it works, let’s write a simple Pet API:
{
install(new OpenAPIModule()); (1)
path("/pets", () { (2)
get("/", ctx -> {
PetRepository repo = ...;
return repo.list();
});
});
}
1 | Install OpenAPIModule |
2 | Write your API |
The OpenAPIModule read from classpath the generated json
and yaml
files. To generate
them you need to build your project.
mvn clean package
./gradlew build
You will find the files in the output build directory. If your application is bar.Foo
, then:
target/classes/bar/Foo.json target/classes/bar/Foo.yaml
build/classes/java/main/bar/Foo.json build/classes/java/main/bar/Foo.yaml
This is the main difference with previous version. We moved from runtime to build time generation. This way we:
|
The OpenAPI generator works exactly the same for MVC routes (a.k.a Controller):
{
install(new OpenAPIModule());
mvc(new Pets());
}
@Path("/pets")
public class Pets {
@GET
public List<Pet> list() {
...
}
}
The Maven plugin and Gradle task provide two filter properties includes
and excludes
. These
properties filter routes by their path pattern. The filter is a regular expression.
1.3. Annotations
To produces a better documentation this plugin depends on some OpenAPI annotations. To use them, you need to add a dependency to your project:
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.25</version>
</dependency>
Once you added to your project, you can annotate your routes:
import io.swagger.v3.oas.annotations.Operation;
...
public class App extends Jooby {
{
path("/pets", () -> {
get("/{id}", this::findPetById)
});
}
@Operation(
summary = "Find a pet by ID",
description = "Find a pet by ID or throws a 404"
)
public Pet findPetById(Context ctx) {
PetRepo repo = require(PetRepo.class);
long id = ctx.path("id").longValue();
return repo.find(id);
}
}
The OpenAPI annotations complement the openAPI byte code parser by adding documentation or being more specific about a operation, parameter, response type, response status, etc.
Annotations works as documentation but also as a way to override what was generated by the byte code parser.
Annotations are supported at script routes (using the technique described before) and mvc routes.
If you look at the example, there is no documentation for path parameter: id
, still this parameter
is going to be present in the OpenAPI files (present, but without documentation).
To add documentation just do:
@Operation( summary = "Find a pet by ID", description = "Find a pet by ID or throws a 404", parameters = @Parameter(description = "Pet ID") )
If the parameter annotation doesn’t specify a name, parameter binding follows a positional assignment.
1.3.1. OpenAPIDefinition
This annotation is supported at the application level:
@OpenAPIDefinition(
info = @Info(
title = "Title",
description = "description",
termsOfService = "Terms",
contact = @Contact(
name = "Jooby",
url = "https://jooby.io",
email = "support@jooby.io"
),
license = @License(
name = "Apache",
url = "https://jooby.io/LICENSE"
),
version = "10"
),
tags = @Tag(name = "mytag")
)
class App extends Jooby {
{
// All routes now have the default tag: `Pets`
}
}
1.3.2. Tags
Tagging is supported at three different levels:
@Tag(name = "Pets", description = "Pet operations")
class App extends Jooby {
{
// All routes now have the default tag: `Pets`
}
}
@Tag(name = "Pets", description = "Pet operations")
@Path("/pets")
class Pets {
// All web method now have the default tag: `Pets`
}
@Tag(name = "Pets", description = "Pet operations")
public List<Pet> list(Context ctx) {
...
}
For multiple tags use the @Tags
annotation or the tags
property of @OpenAPIDefinition
and/or @Operation
annotations.
1.3.3. Responses & Status
The default response code is Success(200)
(or NO_CONTENT(204)
for DELETE mvc routes). Now, if
you need to:
-
document the default response
-
use a custom response code
-
use multiple response codes
You need the ApiResponse
annotation:
@ApiResponse(description = "This is the default response")
@ApiResponse(responseCode = "201", description = "This is the default response")
@ApiResponses({ @ApiResponse(description = "This is the default response"), @ApiResponse(responseCode = "500"), @ApiResponse(responseCode = "400"), @ApiResponse(responseCode = "404") })
1.4. Documentation Template
The OpenAPI output generates some default values for info
and server
section. It generates
the necessary to follow the specification and produces a valid output. These sections can be override
with better information/metadata.
To do so just write an openapi.yaml
file inside the conf
directory to use it as template.
openapi: 3.0.1
info:
title: My Super API
description: |
Nunc commodo ipsum vitae dignissim congue. Quisque convallis malesuada tortor, non
lacinia quam malesuada id. Curabitur nisi mi, lobortis non tempus vel, vestibulum et neque.
...
version: "1.0"
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
paths:
/api/pets:
get:
operationId: listPets
description: List and sort pets.
parameters:
name: page
descripton: Page number.
All sections from template file are merged into the final output.
The extension property: x-merge-policy
controls how merge must be done:
-
ignore: Silently ignore a path or operation present in template but not found in generated output. This is the default value.
-
keep: Add a path or operation to final output. Must be valid path or operation.
-
fail: Throw an error when path or operation is present in template but not found in generated output.
The extension property can be added at root/global level, paths, pathItem, operation or parameter level.
Keep in mind that any section found here in the template overrides existing metadata. |
1.5. Swagger UI
To use swagger-ui just add the dependency to your project:
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-swagger-ui</artifactId>
<version>3.5.3</version>
</dependency>
The swagger-ui application will be available at /swagger
. To modify the default path, just call swaggerUI(String)
1.6. Redoc
To use redoc just add the dependency to your project:
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-redoc</artifactId>
<version>3.5.3</version>
</dependency>
The redoc application will be available at /redoc
. To modify the default path, just call redoc(String)