juneau-bean-openapi-v3
The juneau-bean-openapi-v3 module provides Java beans for working with OpenAPI 3.0 documents and user interfaces.
Overview
This module contains predefined POJOs for:
- OpenAPI 3.0 document structure
- API documentation generation
- OpenAPI UI rendering
- Schema validation
OpenAPI Documents
The Juneau OpenAPI DTO beans are simply beans with fluent-style setters that allow you to quickly construct OpenAPI documents as Java objects. These objects can then be serialized to JSON using one of the existing JSON serializers, or to other languages such as XML or HTML using the other serializers.
The OpenApiBuilder class is a utility class with predefined static methods that allow you to easily construct DTO bean instances in a minimal amount of code.
The following is an example OpenAPI document:
{
"openapi": "3.0.0",
"info": {
"title": "Pet Store API",
"description": "This is a sample server Petstore server.",
"version": "1.0.0",
"contact": {
"email": "apiteam@example.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"servers": [
{
"url": "https://petstore.example.com/v2"
}
],
"tags": [
{
"name": "pet",
"description": "Everything about your Pets"
}
],
"paths": {
"/pet": {
"post": {
"tags": ["pet"],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"requestBody": {
"description": "Pet object that needs to be added to the store",
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"405": {
"description": "Invalid input"
}
}
}
}
}
}
This document can be generated by the following Java code:
import static org.apache.juneau.bean.openapi3.OpenApiBuilder.*;
import java.net.URI;
import java.util.Map;
OpenApi openApi = openApi()
.setOpenapi("3.0.0")
.setInfo(
info("Pet Store API", "1.0.0")
.setDescription("This is a sample server Petstore server.")
.setContact(
contact().setEmail("apiteam@example.com")
)
.setLicense(
license("Apache 2.0").setUrl(URI.create("http://www.apache.org/licenses/LICENSE-2.0.html"))
)
)
.setServers(
server(URI.create("https://petstore.example.com/v2"))
)
.setTags(
tag("pet").setDescription("Everything about your Pets")
)
.addPath("/pet",
pathItem().setPost(
operation()
.addTags("pet")
.setSummary("Add a new pet to the store")
.setDescription("")
.setOperationId("addPet")
.setRequestBody(
requestBodyInfo()
.setDescription("Pet object that needs to be added to the store")
.setRequired(true)
.setContent(
Map.of("application/json", mediaType().setSchema(schemaInfo().setType("object")))
)
)
.addResponse("405", response("Invalid input"))
)
);
// Serialize using JSON serializer.
String openApiJson = Json.of(openApi);
// Or just use toString().
openApiJson = openApi.toString();
A few things to note when comparing this to the (superficially similar) Swagger 2.0 API on juneau-bean-swagger2:
- OpenAPI v3 paths are added with
OpenApi.addPath(String path, PathItem pathItem)— a 2-argument method that takes a fully-builtPathItem. This differs from Swagger v2'sSwagger.addOperation(String path, String method, Operation operation)(also available under its original name,Swagger.addPath(...), for backwards compatibility), a 3-argument method that adds a single operation directly. Individual HTTP methods on an OpenAPI v3PathItemare set viasetGet(Operation)/setPost(Operation)/etc. - Request bodies use
RequestBodyInfo(via therequestBodyInfo()factory), notrequestBody()/schema()static factories — those don't exist in this package. RequestBodyInfo.setContent(...)andResponse.setContent(...)both take aMap<String,MediaType>, keyed by media type string, with eachMediaTypebuilt viamediaType().setSchema(SchemaInfo).
OpenAPI UI
The OpenApiUI class is a DTO bean class for generating OpenAPI user interfaces from OpenApi beans.
The class itself is nothing more than a POJO swap that swaps out OpenApi beans with Div elements.
public class OpenApiUI extends ObjectSwap {
@Override
public MediaType[] forMediaTypes() {
// Only use this swap when the Accept type is HTML.
return new MediaType[] {MediaType.HTML};
}
@Override
public Div swap(MarshallingSession session, OpenApi openApi) throws Exception {
// Generate HTML UI for OpenAPI document
...
}
}
Usage in REST Services
The BasicRestServlet class exposes the OpenAPI document for a resource through a built-in OPTIONS /* operation; content negotiation (e.g. requesting text/html) determines whether the OpenApiUI swap is applied when rendering it:
@Rest(
// Allow OPTIONS requests to be simulated using ?method=OPTIONS query parameter.
allowedMethodParams="OPTIONS",
mixins={SwaggerUiMixin.class, RedocMixin.class, ErrorMixin.class, HtdocMixin.class, StatsMixin.class, FaviconMixin.class},
...
)
public abstract class BasicRestServlet extends RestServlet implements BasicUniversalConfig {
/**
* [OPTIONS /*] - Show resource options.
*/
@RestOp(
method=OPTIONS,
path="/*",
summary="OpenAPI documentation",
description="OpenAPI documentation for this resource."
)
@HtmlDocConfig(
// Override the nav links for the OpenAPI page.
navlinks={
"back: servlet:/",
"json: servlet:/?method=OPTIONS&Accept=text/json&plainText=true"
},
// Never show aside contents of page inherited from class.
aside="NONE"
)
public OpenApi getOptions(RestRequest req) {
// Localized OpenAPI for this resource is available through the RestRequest object.
return req.getOpenApi().orElseThrow();
}
}
Dependencies
- No external dependencies
- Part of the
juneau-beanmodule group