Quarkus - Using OpenAPI and Swagger UI
This guide explains how your Quarkus application can expose its API description through an OpenAPI specification andhow you can test it via a user-friendly UI named Swagger UI.
Prerequisites
To complete this guide, you need:
less than 15 minutes
an IDE
JDK 1.8+ installed with
JAVA_HOME
configured appropriatelyApache Maven 3.5.3+
Architecture
In this guide, we create a straightforward REST application to demonstrate how fast you can expose your APIspecification and benefit from a user interface to test it.
Solution
We recommend that you follow the instructions in the next sections and create the application step by step.However, you can skip right to the completed example.
Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git
, or download an archive.
The solution is located in the openapi-swaggerui-quickstart
directory.
Creating the Maven project
First, we need a new project. Create a new project with the following command:
mvn io.quarkus:quarkus-maven-plugin:1.0.0.CR1:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=openapi-swaggerui-quickstart \
-DclassName="org.acme.openapi.swaggerui.FruitResource" \
-Dpath="/fruits" \
-Dextensions="resteasy-jsonb"
cd openapi-swaggerui-quickstart
This command generates the Maven project with a /fruits
REST endpoint.
Expose a REST Resource
We will create a Fruit
bean and a FruitResouce
REST resource(feel free to take a look to the Writing JSON REST services guide if your want more details on how to build a REST API with Quarkus).
package org.acme.openapi.swaggerui;
public class Fruit {
public String name;
public String description;
public Fruit() {
}
public Fruit(String name, String description) {
this.name = name;
this.description = description;
}
}
package org.acme.openapi.swaggerui;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;
@Path("/fruits")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class FruitResource {
private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));
public FruitResource() {
fruits.add(new Fruit("Apple", "Winter fruit"));
fruits.add(new Fruit("Pineapple", "Tropical fruit"));
}
@GET
public Set<Fruit> list() {
return fruits;
}
@POST
public Set<Fruit> add(Fruit fruit) {
fruits.add(fruit);
return fruits;
}
@DELETE
public Set<Fruit> delete(Fruit fruit) {
fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
return fruits;
}
}
As we changed the API, we also need to update the test:
package org.acme.openapi.swaggerui;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import javax.ws.rs.core.MediaType;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsInAnyOrder;
@QuarkusTest
public class FruitResourceTest {
@Test
public void testList() {
given()
.when().get("/fruits")
.then()
.statusCode(200)
.body("$.size()", is(2),
"name", containsInAnyOrder("Apple", "Pineapple"),
"description", containsInAnyOrder("Winter fruit", "Tropical fruit"));
}
@Test
public void testAdd() {
given()
.body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}")
.header("Content-Type", MediaType.APPLICATION_JSON)
.when()
.post("/fruits")
.then()
.statusCode(200)
.body("$.size()", is(3),
"name", containsInAnyOrder("Apple", "Pineapple", "Pear"),
"description", containsInAnyOrder("Winter fruit", "Tropical fruit", "Winter fruit"));
given()
.body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}")
.header("Content-Type", MediaType.APPLICATION_JSON)
.when()
.delete("/fruits")
.then()
.statusCode(200)
.body("$.size()", is(2),
"name", containsInAnyOrder("Apple", "Pineapple"),
"description", containsInAnyOrder("Winter fruit", "Tropical fruit"));
}
}
Expose OpenAPI Specifications
Quarkus proposes a smallrye-openapi
extension compliant with the Eclipse MicroProfile OpenAPIspecification in order to generate your API OpenAPI v3 specification.
You just need to add the openapi
extension to your Quarkus application:
./mvnw quarkus:add-extension -Dextensions="openapi"
Now, we are ready to run our application:
./mvnw compile quarkus:dev
Once your application is started, you can make a request to the default /openapi
endpoint:
$ curl http://localhost:8080/openapi
openapi: 3.0.1
info:
title: Generated API
version: "1.0"
paths:
/fruits:
get:
responses:
200:
description: OK
content:
application/json: {}
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Fruit'
responses:
200:
description: OK
content:
application/json: {}
delete:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Fruit'
responses:
200:
description: OK
content:
application/json: {}
components:
schemas:
Fruit:
properties:
description:
type: string
name:
type: string
If you do not like the default endpoint location /openapi , you can change it by adding the following configuration to your application.properties :
|
Hit CTRL+C
to stop the application.
Loading OpenAPI Schema From Static Files
Instead of dynamically creating OpenAPI schemas from annotation scanning, Quarkus also supports serving static OpenAPI documents.The static file to serve must be a valid document conforming to the OpenAPI specification.An OpenAPI document that conforms to the OpenAPI Specification is itself a valid JSON object, that can be represented in yaml
or json
formats.
To see this in action, we’ll put OpenAPI documentation under META-INF/openapi.yaml
for our /fruits
endpoints.Quarkus also supports alternative OpenAPI document paths if you prefer.
openapi: 3.0.1
info:
title: Static OpenAPI document of fruits resource
description: Fruit resources Open API documentation
version: "1.0"
servers:
- url: http://localhost:8080/openapi
description: Optional dev mode server description
paths:
/fruits:
get:
responses:
200:
description: OK - fruits list
content:
application/json: {}
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Fruit'
responses:
200:
description: new fruit resource created
content:
application/json: {}
delete:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Fruit'
responses:
200:
description: OK - fruit resource deleted
content:
application/json: {}
components:
schemas:
Fruit:
properties:
description:
type: string
name:
type: string
By default, a request to /openapi
will serve the combined OpenAPI document from the static file and the model generated from application endpoints code.We can however change this to only serve the static OpenAPI document by adding mp.openapi.scan.disable=true
configuration into application.properties
.
Now, a request to /openapi
endpoint will serve the static OpenAPI document instead of the generated one.
About OpenAPI document pathsQuarkus supports various paths to store your OpenAPI document under. We recommend you place it under META-INF/openapi.yml .Alternative paths are:-META-INF/openapi.yaml -META-INF/openapi.yml -META-INF/openapi.json -WEB-INF/classes/META-INF/openapi.yml -WEB-INF/classes/META-INF/openapi.yaml -WEB-INF/classes/META-INF/openapi.json Live reload of static OpenAPI document is supported during development. A modification to your OpenAPI document will be picked up on fly by Quarkus. |
Use Swagger UI for development
When building APIs, developers want to test them quickly. Swagger UI is a great toolpermitting to visualize and interact with your APIs.The UI is automatically generated from your OpenAPI specification.
The Quarkus smallrye-openapi
extension comes with a swagger-ui
extension embedding a properly configured Swagger UI page.
By default, Swagger UI is only available when Quarkus is started in dev or test mode.If you want to make it available in production too, you can include the following configuration in your application.properties :
|
By default, Swagger UI is accessible at /swagger-ui
.
You can update this path by setting the quarkus.swagger-ui.path
property in your application.properties
:
quarkus.swagger-ui.path=/my-custom-path
The value / is not allowed as it blocks the application from serving anything else. |
Now, we are ready to run our application:
./mvnw compile quarkus:dev
You can check the Swagger UI path in your application’s log:
00:00:00,000 INFO [io.qua.swa.run.SwaggerUiServletExtension] Swagger UI available at /swagger-ui
Once your application is started, you can go to http://localhost:8080/swagger-ui and play with your API.
You can visualize your API’s operations and schemas.
You can also interact with your API in order to quickly test it.
Hit CTRL+C
to stop the application.
Configuration Reference
OpenAPI
Configuration property fixed at build time - ️ Configuration property overridable at runtime
Configuration property | Type | Default |
---|---|---|
quarkus.smallrye-openapi.path The path at which to register the OpenAPI Servlet. | string | /openapi |
Swagger UI
Configuration property fixed at build time - ️ Configuration property overridable at runtime
Configuration property | Type | Default |
---|---|---|
quarkus.swagger-ui.path The path of the swagger-ui servlet. The value / is not allowed as it blocks the application from serving anything else. | string | /swagger-ui |
quarkus.swagger-ui.always-include If this should be included every time. By default this is only included when the application is running in dev mode. | boolean | false |