From 6bdf7dfec679aa1f30951b0d6b55a9d1aa4b7342 Mon Sep 17 00:00:00 2001 From: altro3 Date: Fri, 20 Sep 2024 18:31:04 +0700 Subject: [PATCH] Autogenerate Info block for openAPI spec --- .../visitor/OpenApiApplicationVisitor.java | 21 ++++ .../visitor/OpenApiConfigProperty.java | 8 +- .../OpenApiApplicationVisitorSpec.groovy | 98 ++++++++++++++----- 3 files changed, 102 insertions(+), 25 deletions(-) diff --git a/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiApplicationVisitor.java b/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiApplicationVisitor.java index 89d6c28571..2c1643bcef 100644 --- a/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiApplicationVisitor.java +++ b/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiApplicationVisitor.java @@ -47,6 +47,7 @@ import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.Paths; import io.swagger.v3.oas.models.SpecVersion; +import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.servers.Server; @@ -97,6 +98,7 @@ import static io.micronaut.openapi.visitor.FileUtils.openApiSpecFile; import static io.micronaut.openapi.visitor.FileUtils.resolve; import static io.micronaut.openapi.visitor.OpenApiConfigProperty.ALL; +import static io.micronaut.openapi.visitor.OpenApiConfigProperty.MICRONAUT_APPLICATION_NAME; import static io.micronaut.openapi.visitor.OpenApiConfigProperty.MICRONAUT_OPENAPI_ADDITIONAL_FILES; import static io.micronaut.openapi.visitor.OpenApiConfigProperty.MICRONAUT_OPENAPI_ADOC_ENABLED; import static io.micronaut.openapi.visitor.OpenApiConfigProperty.MICRONAUT_OPENAPI_CONTEXT_SERVER_PATH; @@ -126,6 +128,9 @@ */ public class OpenApiApplicationVisitor extends AbstractOpenApiVisitor implements TypeElementVisitor { + public static final String DEFAULT_OPENAPI_TITLE = "Service"; + public static final String DEFAULT_OPENAPI_VERSION = "1.0.0"; + private static final int MAX_ITERATIONS = 100; private ClassElement classElement; private int visitedElements = -1; @@ -690,6 +695,7 @@ public int getOrder() { private OpenAPI postProcessOpenApi(OpenAPI openApi, VisitorContext context) { + fixInfoBlockIfNeeded(openApi, context); applyPropertyNamingStrategy(openApi, context); applyPropertyServerContextPath(openApi, context); @@ -710,6 +716,21 @@ private OpenAPI postProcessOpenApi(OpenAPI openApi, VisitorContext context) { return openApi; } + private void fixInfoBlockIfNeeded(OpenAPI openApi, VisitorContext context) { + + if (openApi.getInfo() == null) { + openApi.setInfo(new Info()); + } + var info = openApi.getInfo(); + if (info.getTitle() == null) { + String applicationName = ConfigUtils.getConfigProperty(MICRONAUT_APPLICATION_NAME, context); + info.setTitle(applicationName != null ? applicationName : DEFAULT_OPENAPI_TITLE); + } + if (info.getVersion() == null) { + info.setVersion(DEFAULT_OPENAPI_VERSION); + } + } + public static void removeUnusedSchemas(OpenAPI openApi) { int i = 0; // remove unused schemas diff --git a/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiConfigProperty.java b/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiConfigProperty.java index 0b1f751d5a..471ad75306 100644 --- a/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiConfigProperty.java +++ b/openapi/src/main/java/io/micronaut/openapi/visitor/OpenApiConfigProperty.java @@ -191,11 +191,15 @@ public interface OpenApiConfigProperty { */ String MICRONAUT_OPENAPI_JSON_VIEW_DEFAULT_INCLUSION = "micronaut.openapi.json.view.default.inclusion"; /** - * Loaded micronaut-http server context path property. + * micronaut-http server context path property. */ String MICRONAUT_SERVER_CONTEXT_PATH = "micronaut.server.context-path"; /** - * Loaded micronaut-http-server-netty property (json-view.enabled). + * micronaut-context application name property. + */ + String MICRONAUT_APPLICATION_NAME = "micronaut.application.name"; + /** + * micronaut-http-server-netty property (json-view.enabled). */ String MICRONAUT_JACKSON_JSON_VIEW_ENABLED = "jackson.json-view.enabled"; diff --git a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiApplicationVisitorSpec.groovy b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiApplicationVisitorSpec.groovy index e133748d0d..5263018065 100644 --- a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiApplicationVisitorSpec.groovy +++ b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiApplicationVisitorSpec.groovy @@ -4,9 +4,11 @@ import io.micronaut.context.env.Environment import io.micronaut.openapi.AbstractOpenApiTypeElementSpec import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.security.SecurityScheme +import spock.util.environment.RestoreSystemProperties class OpenApiApplicationVisitorSpec extends AbstractOpenApiTypeElementSpec { + @RestoreSystemProperties void "test build OpenAPI doc for simple endpoint"() { given:"An API definition" System.setProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_CONFIG_FILE, "openapi-endpoints.properties") @@ -434,9 +436,6 @@ class MyBean {} openAPI.paths[uri].post.parameters.size() == 1 openAPI.paths[uri].post.parameters[0].name ==~ /arg0|name/ openAPI.paths[uri].post.requestBody - - cleanup: - System.clearProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_CONFIG_FILE) } void "test build OpenAPI doc for simple type with generics"() { @@ -772,11 +771,10 @@ class MyBean {} oauth2.scheme == null } + @RestoreSystemProperties void "test disable openapi"() { given: "An API definition" - Utils.testReference = null - Utils.testReferences = null System.setProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_ENABLED, "false") when: @@ -835,16 +833,12 @@ class MyBean {} ''') then: "the state is correct" !Utils.testReference - - cleanup: - System.clearProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_ENABLED) } + @RestoreSystemProperties void "test disable openapi from file"() { given: "An API definition" - Utils.testReference = null - Utils.testReferences = null System.setProperty(OpenApiConfigProperty.MICRONAUT_CONFIG_FILE_LOCATIONS, "project:/src/test/resources/") System.setProperty(Environment.ENVIRONMENTS_PROPERTY, "disabled-openapi") @@ -900,17 +894,12 @@ class MyBean {} ''') then: "the state is correct" !Utils.testReference - - cleanup: - System.clearProperty(OpenApiConfigProperty.MICRONAUT_CONFIG_FILE_LOCATIONS) - System.clearProperty(Environment.ENVIRONMENTS_PROPERTY) } + @RestoreSystemProperties void "test disable openapi from openapi.properties file"() { given: "An API definition" - Utils.testReference = null - Utils.testReferences = null System.setProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_CONFIG_FILE, "openapi-disabled-openapi.properties") when: @@ -965,16 +954,12 @@ class MyBean {} ''') then: "the state is correct" !Utils.testReference - - cleanup: - System.clearProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_CONFIG_FILE) } + @RestoreSystemProperties void "test build OpenAPIDefinition with placeholders"() { given: "An API definition" - Utils.testReference = null - Utils.testReferences = null System.setProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_CONFIG_FILE, "openapi-placeholders.properties") when: @@ -1008,8 +993,75 @@ class MyBean {} openAPI.info.title == "broken-micronaut-openapi-expand" openAPI.info.description == 'monkey' openAPI.info.version == '2.2.2' + } + + void "test auto generated info block"() { + when: + buildBeanDefinition('test.MyBean', ''' +package test; - cleanup: - System.clearProperty(OpenApiConfigProperty.MICRONAUT_OPENAPI_CONFIG_FILE) +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; + +@Controller +class MyController { + + @Get("/get") + public String get() { + return null; + } +} + +@jakarta.inject.Singleton +class MyBean {} +''') + then: + Utils.testReference != null + + when: + OpenAPI openAPI = Utils.testReference + + then: + openAPI.info + openAPI.info.title == OpenApiApplicationVisitor.DEFAULT_OPENAPI_TITLE + openAPI.info.version == OpenApiApplicationVisitor.DEFAULT_OPENAPI_VERSION + } + + @RestoreSystemProperties + void "test auto generated info block with application name"() { + + given: + def serviceName = "This is my service" + System.setProperty(OpenApiConfigProperty.MICRONAUT_APPLICATION_NAME, serviceName) + + when: + buildBeanDefinition('test.MyBean', ''' +package test; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; + +@Controller +class MyController { + + @Get("/get") + public String get() { + return null; + } +} + +@jakarta.inject.Singleton +class MyBean {} +''') + then: + Utils.testReference != null + + when: + OpenAPI openAPI = Utils.testReference + + then: + openAPI.info + openAPI.info.title == serviceName + openAPI.info.version == OpenApiApplicationVisitor.DEFAULT_OPENAPI_VERSION } }