flak-swagger generates an OpenAPI
specification from the route handlers of an application. What Flak knows,
such as routes, methods, parameters and JSON types, is filled in
automatically, as Flak binds them. The rest can be added with
Swagger annotations.
implementation "com.github.pcdv.flak:flak-swagger:3.2.1"OpenApiGenerator gen = new OpenApiGenerator();
gen.setObjectMapper(mapper); // the mapper used for JSON, if configured
gen.scan(app);
gen.getAPI().info(new Info().title("Shop API").version("1.0"));
String yaml = gen.toYaml();
String json = gen.toJSON();scan(app) describes every route of the app, once they are all registered:
those added later are not described. When an app serves several APIs, each
documented on its own, scan the classes of one API instead:
gen.scan(ItemRoutes.class);
gen.scan(OrderRoutes.class);This describes the @Route methods declared by those classes, and nothing
else. Not knowing the app, it differs in three ways:
- paths are written as in
@Route, without the path of the app or the prefix given toscan(obj, prefix) - what is JSON is told by
@JSON, on the method, its class or a parameter - the custom extractors of the app are unknown, so a request body is only
described for handlers reading JSON: the parameter with
@JSON, or else the last parameter that could be a body
getAPI() returns the OpenAPI object of swagger-core, which can be
completed at will (info, servers, security schemes…) before it is written.
The specification can be served by the application itself:
@Route("/api/openapi.yaml")
public String openApi() {
return yaml;
}For each route handler, static resources excepted:
-
the path, as the app serves it with
scan(app): prefixed with the path of the app and with the prefix given toscan(obj, prefix), if any. Its variables are in OpenAPI syntax:/items/:idbecomes/items/{id}, and so does a splat,/files/*pathbecoming/files/{path}. -
the operation, for its HTTP method,
@Headincluded. Its id is the name of the Java method. -
tags: those of
@Tagon the method, or else on the class, or else the simple name of the class -
parameters:
- every variable of the route, as a path parameter of type
stringorinteger - every
@QueryParam, with its type, default value, description, and whether it is required - every property of a
@QueryParamsobject, as Jackson binds it, with its type, the value it is initialized with as default, its description, e.g. from@JsonPropertyDescription, and whether it is required, e.g. with@JsonProperty(required = true)(since 3.1.0). Jackson introspects it with the mapper the handler binds it with, e.g. the one of its@JSON("id"), whenscan(App)describes it (since 3.2.1), and with the mapper of the generator otherwise. - those declared with
@Parameteron the method, which take precedence over a path variable of the same name
A
@Parameteron a parameter completes what Flak knows of it, without repeating its name, location or type, e.g.@Parameter(required = true, example = "42") @QueryParam("id") String id.@Parameter(hidden = true)leaves it out. A description alone is shorter with@QueryParam(value = "id", description = "..."). - every variable of the route, as a path parameter of type
-
the request body: what
@RequestBodydeclares, or else the schema of the parameter parsed from the body, asapplication/jsonwhen it is read as JSON. A form is described asapplication/x-www-form-urlencoded(since 3.2.0): a@FormParamsobject with its properties, described as those of@QueryParams, and aFormwith string fields, which@RequestBodycan list. -
the response: a 200 with the schema of the return type, as
application/jsonwith@JSON, and no content for avoidhandler.@ApiResponseannotations replace it, for instance to document several status codes, or another one set by the handler. -
descriptions, from
@Operation(summary = ..., description = ...). A description of the forminclude:docs/items.mdis read from that classpath resource, so long descriptions can live in files.
Schemas are derived from the Java types with swagger-core. Call
setObjectMapper() before scanning, so that they follow the Jackson settings
of the application, e.g. ignored properties or naming strategies.
scanSchema(type) adds the schema of a type that no handler mentions
directly, such as a subtype listed in @Schema(oneOf = ...).
setRemovePrefix("/api") strips a common prefix from all paths, e.g. to
declare it once in servers.