My current project with Jersey has several applications.
(org.glassfish.jersey.server.ResourceConfig extends javax.ws.rs.core.Application)
I have added Swagger documentation to the project, but I would like to have different urls with different resource methods for different applications. Something like:
https://our.company.name:8080/project/**${APPLICATION_NAME}**/openapi.json
At the moment, all resource methods in all applications are added to a single openapi.json that is displayed on any of the urls. How can I split it?
pom:
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>2.1.5</version>
</dependency>
One of the Applications example:
public SomeApplication(@Context ServletConfig servletConfig) {
final String[] packages = {"com.projectname.rest.SOMEAPPLICATION.api","io.swagger.v3.jaxrs2.integration.resources"};
packages(packages);
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
register(CorsResponseFilter.class);
register(UnknownParameterRequestFilter.class);
register(BTSMarshallingFeature.class);
SwaggerManager swaggerManager = new SwaggerManager();
OpenAPI oas = new OpenAPI();
Info info = new Info();
info.setTitle("SOMEAPPLICATION Public API Documentation");
info.setVersion("v1");
info.setDescription("description...");
oas.info(info);
SecurityScheme securitySchemeApiKey = new SecurityScheme();
securitySchemeApiKey.setName("Token");
securitySchemeApiKey.setType(io.swagger.v3.oas.models.security.SecurityScheme.Type.APIKEY);
securitySchemeApiKey.setIn(io.swagger.v3.oas.models.security.SecurityScheme.In.HEADER);
oas.schemaRequirement(securitySchemeApiKey.getName(), securitySchemeApiKey);
oas.servers(Collections.singletonList(new Server().url("/s1")));
SwaggerConfiguration oasConfig = new SwaggerConfiguration().openAPI(oas).prettyPrint(true).readAllResources(false).resourcePackages(Stream.of("com.projectname.rest.SOMEAPPLICATION.api").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder<>().servletConfig(servletConfig).application(config).openApiConfiguration(oasConfig).buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
html page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<!--<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">-->
<link href="../swagger/swagger-ui.css" rel="stylesheet" type="text/css">
<!--<link rel="stylesheet" type="text/css" href=".../swagger/css/swagger.css" >-->
<link href="../swagger/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png"/>
<link href="../swagger/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png"/>
<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/swagger-ui-bundle.js"></script>
<script src="../swagger/swagger-ui-standalone-preset.js"></script>
<script src="../script/swagger_APPLICATION_NAME_api.js"></script>
</body>
</html>
swagger_APPLICATION_NAME_api.js:
var versionNumber = "v2";
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
}
window.onload = function () {
var versionParam = getUrlParameter("version");
if (versionParam) {
versionNumber = versionParam;
}
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
}
var swaggerUrl = window.location.origin + "/s1/APPLICATION_NAME/openapi.json";
const ui = SwaggerUIBundle({
url: swaggerUrl,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
plugins: [SwaggerUIBundle.plugins.DownloadUrl],
layout: "StandaloneLayout",
operationsSorter: (a, b) => {
var result = a.get("path").localeCompare(b.get("path"));
if (result === 0) {
var methodsOrder = ["get", "post", "put", "delete", "patch", "options", "trace"];
result = methodsOrder.indexOf(a.get("method")) - methodsOrder.indexOf(b.get("method"));
}
return result;
},
tagsSorter: "alpha"
});
window.ui = ui;
};
Resource method example:
@Operation(
tags = {"Dummy"}, method = "GET", summary = "gets example list",
description = "Returns a List of Strings",
responses = {
@ApiResponse(responseCode = "200", description = "OK",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = String.class)
)
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "422", description = "Validation error"),
@ApiResponse(responseCode = "500", description = "Internal server error", headers={
@Header(name = "X-P8-Information", description = "Request has errors.")
})
}
)
public Response getDummy() {
return respondGet(List.of("APPLICATION_MAME", "Dummy", "Response"));
}
I think I have this result because we have a Singleton here:
package io.swagger.v3.oas.integration;
public class GenericOpenApiContextBuilder<T extends GenericOpenApiContextBuilder> implements
OpenApiContextBuilder {
@Override
public OpenApiContext buildContext(boolean init) throws OpenApiConfigurationException {
if (StringUtils.isBlank(ctxId)) {
ctxId = OpenApiContext.OPENAPI_CONTEXT_ID_DEFAULT;
}
OpenApiContext ctx = OpenApiContextLocator.getInstance().getOpenApiContext(ctxId);
}
...
}
I have tried to set unique ctxId for each Application. The results are:
- Same behavior for methods.
- Info (title, version... ) was missing.