Skip to content

Commit

Permalink
Merge pull request #25800 from phillip-kruger/openapi-js
Browse files Browse the repository at this point in the history
OpenAPI enhancement
  • Loading branch information
phillip-kruger authored May 30, 2022
2 parents 3d9c64f + 951e183 commit 1584b8c
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ public final class SmallRyeOpenApiConfig {
@ConfigItem(defaultValue = "true")
public boolean autoAddTags;

/**
* Setting it to `true` will automatically add a default server to the schema if none is provided,
* using the current running server host and port.
*/
@ConfigItem
public Optional<Boolean> autoAddServer;

/**
* This will automatically add security based on the security extension included (if any).
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@
import io.quarkus.security.Authenticated;
import io.quarkus.smallrye.openapi.common.deployment.SmallRyeOpenApiConfig;
import io.quarkus.smallrye.openapi.deployment.filter.AutoRolesAllowedFilter;
import io.quarkus.smallrye.openapi.deployment.filter.AutoServerFilter;
import io.quarkus.smallrye.openapi.deployment.filter.AutoTagFilter;
import io.quarkus.smallrye.openapi.deployment.filter.SecurityConfigFilter;
import io.quarkus.smallrye.openapi.deployment.spi.AddToOpenAPIDefinitionBuildItem;
import io.quarkus.smallrye.openapi.deployment.spi.IgnoreStaticDocumentBuildItem;
import io.quarkus.smallrye.openapi.deployment.spi.OpenApiDocumentBuildItem;
import io.quarkus.smallrye.openapi.runtime.OpenApiConstants;
import io.quarkus.smallrye.openapi.runtime.OpenApiDocumentService;
import io.quarkus.smallrye.openapi.runtime.OpenApiRecorder;
Expand Down Expand Up @@ -290,7 +292,7 @@ OpenApiFilteredIndexViewBuildItem smallryeOpenApiIndex(CombinedIndexBuildItem co
}

@BuildStep
void addSecurityFilter(BuildProducer<AddToOpenAPIDefinitionBuildItem> addToOpenAPIDefinitionProducer,
void addAutoFilters(BuildProducer<AddToOpenAPIDefinitionBuildItem> addToOpenAPIDefinitionProducer,
OpenApiFilteredIndexViewBuildItem apiFilteredIndexViewBuildItem,
SmallRyeOpenApiConfig config) {

Expand Down Expand Up @@ -343,6 +345,11 @@ void addSecurityFilter(BuildProducer<AddToOpenAPIDefinitionBuildItem> addToOpenA
addToOpenAPIDefinitionProducer.produce(new AddToOpenAPIDefinitionBuildItem(autoTagFilter));
}

// Add Auto Server based on the current server details
OASFilter autoServerFilter = getAutoServerFilter(config, false);
if (autoServerFilter != null) {
addToOpenAPIDefinitionProducer.produce(new AddToOpenAPIDefinitionBuildItem(autoServerFilter));
}
}

private OASFilter getAutoSecurityFilter(List<SecurityInformationBuildItem> securityInformationBuildItems,
Expand Down Expand Up @@ -440,6 +447,27 @@ private OASFilter getAutoTagFilter(OpenApiFilteredIndexViewBuildItem apiFiltered
return null;
}

private OASFilter getAutoServerFilter(SmallRyeOpenApiConfig config, boolean defaultFlag) {
if (config.autoAddServer.orElse(defaultFlag)) {
Config c = ConfigProvider.getConfig();

String scheme = "http";
String host = c.getOptionalValue("quarkus.http.host", String.class).orElse("0.0.0.0");
int port;

String insecure = c.getOptionalValue("quarkus.http.insecure-requests", String.class).orElse("enabled");
if (insecure.equalsIgnoreCase("enabled")) {
port = c.getOptionalValue("quarkus.http.port", Integer.class).orElse(8080);
} else {
scheme = "https";
port = c.getOptionalValue("quarkus.http.ssl-port", Integer.class).orElse(8443);
}

return new AutoServerFilter(scheme, host, port);
}
return null;
}

private Map<String, List<String>> getRolesAllowedMethodReferences(
OpenApiFilteredIndexViewBuildItem apiFilteredIndexViewBuildItem) {
List<AnnotationInstance> rolesAllowedAnnotations = new ArrayList<>();
Expand Down Expand Up @@ -651,6 +679,7 @@ private void registerReflectionForApiResponseSchemaSerialization(BuildProducer<R
public void build(BuildProducer<FeatureBuildItem> feature,
BuildProducer<GeneratedResourceBuildItem> resourceBuildItemBuildProducer,
BuildProducer<NativeImageResourceBuildItem> nativeImageResources,
BuildProducer<OpenApiDocumentBuildItem> openApiDocumentProducer,
OpenApiFilteredIndexViewBuildItem openApiFilteredIndexViewBuildItem,
Capabilities capabilities,
List<AddToOpenAPIDefinitionBuildItem> openAPIBuildItems,
Expand Down Expand Up @@ -687,11 +716,9 @@ public void build(BuildProducer<FeatureBuildItem> feature,
nativeImageResources.produce(new NativeImageResourceBuildItem(name));
}

// Store the document if needed
boolean shouldStore = openApiConfig.storeSchemaDirectory.isPresent();
if (shouldStore) {
storeDocument(out, openApiConfig, staticModel, annotationModel, openAPIBuildItems);
}
OpenApiDocument finalStoredOpenApiDocument = storeDocument(out, openApiConfig, staticModel, annotationModel,
openAPIBuildItems);
openApiDocumentProducer.produce(new OpenApiDocumentBuildItem(finalStoredOpenApiDocument));
}

@BuildStep
Expand Down Expand Up @@ -968,7 +995,7 @@ private OpenApiDocument loadDocument(OpenAPI staticModel, OpenAPI annotationMode
return document;
}

private void storeDocument(OutputTargetBuildItem out,
private OpenApiDocument storeDocument(OutputTargetBuildItem out,
SmallRyeOpenApiConfig smallRyeOpenApiConfig,
OpenAPI staticModel,
OpenAPI annotationModel,
Expand All @@ -980,14 +1007,24 @@ private void storeDocument(OutputTargetBuildItem out,
OpenApiDocument document = prepareOpenApiDocument(staticModel, annotationModel, openAPIBuildItems);

document.filter(filter(openApiConfig)); // This usually happens at runtime, so when storing we want to filter here too.
// By default also add the auto generated server
OASFilter autoServerFilter = getAutoServerFilter(smallRyeOpenApiConfig, true);
if (autoServerFilter != null) {
document.filter(autoServerFilter);
}
document.initialize();

for (Format format : Format.values()) {
String name = OpenApiConstants.BASE_NAME + format;
byte[] schemaDocument = OpenApiSerializer.serialize(document.get(), format).getBytes(StandardCharsets.UTF_8);
storeGeneratedSchema(smallRyeOpenApiConfig, out, schemaDocument, format);
// Store the document if needed
boolean shouldStore = smallRyeOpenApiConfig.storeSchemaDirectory.isPresent();
if (shouldStore) {
for (Format format : Format.values()) {
String name = OpenApiConstants.BASE_NAME + format;
byte[] schemaDocument = OpenApiSerializer.serialize(document.get(), format).getBytes(StandardCharsets.UTF_8);
storeGeneratedSchema(smallRyeOpenApiConfig, out, schemaDocument, format);
}
}

return document;
}

private OpenApiDocument prepareOpenApiDocument(OpenAPI staticModel,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.quarkus.smallrye.openapi.deployment.filter;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.microprofile.openapi.OASFilter;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.eclipse.microprofile.openapi.models.servers.Server;

import io.smallrye.openapi.api.models.servers.ServerImpl;

/**
* Automatically add default server if none is provided
*/
public class AutoServerFilter implements OASFilter {

private static final String DESCRIPTION = "Auto generated value";
private static final String HTTP = "http";
private static final String ZEROS = "0.0.0.0";
private static final String LOCALHOST = "localhost";
private static final String URL_PATTERN = "%s://%s:%d";

private final String defaultScheme;
private final String defaultHost;
private final int defaultPort;

public AutoServerFilter(String defaultScheme, String defaultHost, int defaultPort) {
if (defaultScheme == null) {
defaultScheme = HTTP;
}
if (defaultHost == null) {
defaultHost = ZEROS;
}
this.defaultScheme = defaultScheme;
this.defaultHost = defaultHost;
this.defaultPort = defaultPort;
}

@Override
public void filterOpenAPI(OpenAPI openAPI) {

List<Server> servers = openAPI.getServers();
if (servers == null || servers.isEmpty()) {
servers = new ArrayList<>();

// In case of 0.0.0.0, also add localhost
if (this.defaultHost.equals(ZEROS)) {
ServerImpl localhost = new ServerImpl();
localhost.setUrl(getUrl(this.defaultScheme, LOCALHOST, this.defaultPort));
localhost.setDescription(DESCRIPTION);
servers.add(localhost);
}

ServerImpl serverImpl = new ServerImpl();
serverImpl.setUrl(getUrl(this.defaultScheme, this.defaultHost, this.defaultPort));
serverImpl.setDescription(DESCRIPTION);
servers.add(serverImpl);

openAPI.setServers(servers);
}
}

private String getUrl(String scheme, String host, int port) {
return String.format(URL_PATTERN, scheme, host, port);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.smallrye.openapi.deployment.spi;

import io.quarkus.builder.item.SimpleBuildItem;
import io.smallrye.openapi.api.OpenApiDocument;

/**
* The final OpenAPI Document as generated by the Extension.
*/
public final class OpenApiDocumentBuildItem extends SimpleBuildItem {

private final OpenApiDocument openApiDocument;

public OpenApiDocumentBuildItem(OpenApiDocument openApiDocument) {
this.openApiDocument = openApiDocument;
}

public OpenApiDocument getOpenApiDocument() {
return openApiDocument;
}
}

0 comments on commit 1584b8c

Please sign in to comment.