Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.RestApiDocumentationGenerator;
import uk.co.compendiumdev.thingifier.swaggerizer.OpenApiSpecificationVersion;
import uk.co.compendiumdev.thingifier.swaggerizer.ScalarUiPage;
import uk.co.compendiumdev.thingifier.swaggerizer.SwaggerGenerationConfig;
import uk.co.compendiumdev.thingifier.swaggerizer.SwaggerUiPage;
import uk.co.compendiumdev.thingifier.swaggerizer.Swaggerizer;

Expand Down Expand Up @@ -107,7 +108,9 @@ public ThingifierAutoDocGenRouting(
get(
swaggerDownloadPath,
(request, response) -> {
String permissive = request.queryParam("permissive");
final SwaggerGenerationConfig config =
swaggerGenerationConfig(
OpenApiSpecificationVersion.OPENAPI_3_1, request);

response.type("text/html");
response.status(200);
Expand All @@ -119,7 +122,7 @@ public ThingifierAutoDocGenRouting(
System.out.println(
"Possibly incomplete swagger generation, api not defined from model");
}
if (permissive != null) {
if (config.includeMethodNotAllowedEndpoints && !config.includeFieldValidation) {
nameprefix = nameprefix + "permissive-";
}
response.header("Content-Type", "application/octet-stream");
Expand All @@ -130,8 +133,7 @@ public ThingifierAutoDocGenRouting(
// TODO: the swaggerizer could be stored at a class level and allow caching to
// be used for the output
return new Swaggerizer(apiDefn)
.asJsonWithPreferredServer(
permissive != null, HttpRequestOrigin.from(request));
.asJsonWithPreferredServer(config, HttpRequestOrigin.from(request));
});
}

Expand All @@ -144,19 +146,52 @@ private void registerOpenApiEndpoint(
(request, response) -> {
response.type("application/json");
response.status(200);
final boolean permissive = request.queryParam("permissive") != null;
final SwaggerGenerationConfig config =
swaggerGenerationConfig(version, request);
if (request.queryParam("download") != null) {
response.header(
"Content-Disposition",
"attachment; filename=\"%s\""
.formatted(openApiDownloadFilename(path, permissive)));
.formatted(
openApiDownloadFilename(
path,
config.includeMethodNotAllowedEndpoints
&& !config.includeFieldValidation)));
}
return new Swaggerizer(apiDefn)
.asJsonWithPreferredServer(
version, permissive, HttpRequestOrigin.from(request));
.asJsonWithPreferredServer(config, HttpRequestOrigin.from(request));
});
}

private SwaggerGenerationConfig swaggerGenerationConfig(
final OpenApiSpecificationVersion version, final HttpServerRequest request) {
final boolean permissive = request.queryParam("permissive") != null;
final boolean strongSchemas = truthyQueryParam(request.queryParam("strongschema"));

final SwaggerGenerationConfig config = new SwaggerGenerationConfig();
config.openApiSpecificationVersion = version;
config.includeMethodNotAllowedEndpoints = permissive;
config.includeFieldValidation = !permissive || strongSchemas;
config.strongSchemas = strongSchemas;
config.pathParameterPlacement = pathParameterPlacement(request.queryParam("pathparams"));
return config;
}

private boolean truthyQueryParam(final String value) {
if (value == null) {
return false;
}
return !"false".equalsIgnoreCase(value.trim()) && !"0".equals(value.trim());
}

private SwaggerGenerationConfig.PathParameterPlacement pathParameterPlacement(
final String placement) {
if ("operation".equalsIgnoreCase(placement)) {
return SwaggerGenerationConfig.PathParameterPlacement.OPERATION;
}
return SwaggerGenerationConfig.PathParameterPlacement.PATH;
}

private String openApiDownloadFilename(final String path, final boolean permissive) {
final String filename = path.substring(path.lastIndexOf("/") + 1);
if (permissive) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,20 @@ public boolean requiresAuthenticatedScopeForWrites() {
return authenticatedScopeForWrites;
}

/**
* @return configured missing-credential response status code
*/
public int missingRequiredCredentialStatusCode() {
return missingCredentialStatusCode;
}

/**
* @return configured invalid-credential response status code
*/
public int invalidCredentialStatusCode() {
return invalidCredentialStatusCode;
}

/**
* @return configured missing-credential response
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,12 @@ private void applyScopedSessionDocumentationTo(
securitySpec.apiKey(
definition.name(), definition.credentialSourceName());
route.secureWithApiKey(definition.name());
route.addPossibleStatus(
RoutingStatus.returnValue(
definition.missingRequiredCredentialStatusCode()));
route.addPossibleStatus(
RoutingStatus.returnValue(
definition.invalidCredentialStatusCode()));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,32 @@

public class SwaggerGenerationConfig {

public enum PathParameterPlacement {
PATH,
OPERATION
}

// include endpoints with only a 405 status code?
public boolean includeMethodNotAllowedEndpoints = false;
public boolean includeFieldValidation = true;
public boolean strongSchemas = false;
public PathParameterPlacement pathParameterPlacement = PathParameterPlacement.PATH;
public OpenApiSpecificationVersion openApiSpecificationVersion =
OpenApiSpecificationVersion.OPENAPI_3_1;

public SwaggerGenerationConfig copy() {
final SwaggerGenerationConfig copy = new SwaggerGenerationConfig();
copy.includeMethodNotAllowedEndpoints = includeMethodNotAllowedEndpoints;
copy.includeFieldValidation = includeFieldValidation;
copy.strongSchemas = strongSchemas;
copy.pathParameterPlacement = pathParameterPlacement;
copy.openApiSpecificationVersion = openApiSpecificationVersion;
return copy;
}

public SwaggerGenerationConfig copyFor(final OpenApiSpecificationVersion version) {
final SwaggerGenerationConfig copy = copy();
copy.openApiSpecificationVersion = version;
return copy;
}
}
Loading
Loading