Skip to content

Commit

Permalink
minor: update springdoc-openapi-plugin to 1.8.0 (#189)
Browse files Browse the repository at this point in the history
add support for grouped apis in springdoc plugin

Signed-off-by: Robin Maunz <[email protected]>
  • Loading branch information
rmaunz authored Nov 6, 2023
1 parent e4573f7 commit 3252cfe
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 29 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,31 @@ openApiConfigure {

For generating the OpenAPI document the task `clfGenerateOpenApiDocumentation` has to be run.

To provide custom configuration just add the openApi extension configuration block.
### Grouped Apis

In case you are using [grouped api configuration](https://springdoc.org/faq.html#_how_can_i_define_multiple_openapi_definitions_in_one_spring_boot_project) in your project, instead of something like this (as described in [springdoc gradle plugin](https://github.com/springdoc/springdoc-openapi-gradle-plugin#customization))

```groovy
openApi {
groupedApiMappings = [
"http://localhost:8080/v3/api-docs/groupA": "groupA.yaml",
"http://localhost:8080/v3/api-docs/groupB": "groupB.yaml"
]
}
```

you have to use the configuration provided by this plugin, since the port of the spring application will be randomly selected

```groovy
openApiConfigure {
groupedApiMappings = [
"/v3/api-docs/groupA": "groupA.yaml",
"/v3/api-docs/groupB": "groupB.yaml"
]
}
```

To provide other custom configuration just add the openApi extension configuration block.
See https://github.com/springdoc/springdoc-openapi-gradle-plugin#customization.

```groovy
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
id("com.gradle.plugin-publish") version "1.1.0"
}

description = "A opinionated approach to configure a gradle project automatically by convention. It supports to automatically configure various plugins to reduce boilerplate code in gradle projects."
description = "An opinionated approach to configure a gradle project automatically by convention. It supports to automatically configure various plugins to reduce boilerplate code in gradle projects."
group = "io.cloudflight.gradle"

autoConfigure {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ swagger-codegen-plugin = { module = "gradle.plugin.org.hidetake:gradle-swagger-g
# we need to manually upgrade here in order to have the library compatible with jackson
swagger-jersey2-jaxrs = { module = "io.swagger:swagger-jersey2-jaxrs", version = { strictly = "1.6.2" } }

springdoc-openapi-plugin = { module = "org.springdoc:springdoc-openapi-gradle-plugin", version = "1.7.0" }
springdoc-openapi-plugin = { module = "org.springdoc:springdoc-openapi-gradle-plugin", version = "1.8.0" }
exec-fork-plugin = { module = "com.github.psxpaul:gradle-execfork-plugin", version = "0.2.0" }

# we need to manually inject this version because of https://github.com/ronmamo/reflections/issues/273 (we would transitively pull 0.9.2 otherwise)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.cloudflight.gradle.autoconfigure.springdoc.openapi

import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property

enum class OpenApiFormat(val extension: String) {
Expand All @@ -9,4 +10,5 @@ enum class OpenApiFormat(val extension: String) {

abstract class SpringDocOpenApiConfigureExtension {
abstract val fileFormat: Property<OpenApiFormat>
abstract val groupedApiMappings: MapProperty<String, String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ class SpringDocOpenApiConfigurePlugin : Plugin<Project> {
target.plugins.apply(OpenApiGradlePlugin::class.java)

val extension = target.extensions.create(EXTENSION_NAME, SpringDocOpenApiConfigureExtension::class.java)
extension.fileFormat.convention(OpenApiFormat.YAML);
extension.fileFormat.convention(OpenApiFormat.YAML)
extension.groupedApiMappings.convention(emptyMap())
val openapi = target.extensions.getByType(OpenApiExtension::class.java)
configureOpenApiExtension(openapi, extension, target, target.name)
val openApiTask = target.tasks.named("generateOpenApiDocs", OpenApiGeneratorTask::class)
makeOpenApiTaskReactive(openApiTask, openapi)

val documentationTask = target.tasks.register("clfGenerateOpenApiDocumentation") {
it.group = TASK_GROUP
Expand All @@ -49,23 +49,6 @@ class SpringDocOpenApiConfigurePlugin : Plugin<Project> {
}
}

private fun makeOpenApiTaskReactive(openApiTask: TaskProvider<OpenApiGeneratorTask>, openapi: OpenApiExtension) {
// for some reason the springdoc plugin reads the values from the extension during task initialization and uses that as convention for the task properties,
// which results in some values being incorrect. Because of that we reconfigure the properties conventions to directly use the extension properties. And
// add conventions to the extension properties to the expected default values see: https://github.com/springdoc/springdoc-openapi-gradle-plugin/blob/master/src/main/kotlin/org/springdoc/openapi/gradle/plugin/OpenApiGeneratorTask.kt#L46
openApiTask.configure {
it.apiDocsUrl.convention(openapi.apiDocsUrl)
it.outputFileName.convention(openapi.outputFileName)
it.groupedApiMappings.convention(openapi.groupedApiMappings)
it.outputDir.convention(openapi.outputDir)
}

openapi.apiDocsUrl.convention("http://localhost:8080/v3/api-docs")
openapi.outputFileName.convention("openapi.json")
openapi.groupedApiMappings.convention(emptyMap())
openapi.outputDir.convention(openApiTask.flatMap { it.project.layout.buildDirectory })
}

private fun `setupWorkaroundFor#171`(target: Project, openapi: OpenApiExtension) {
val forkedSpringBootRun = target.tasks.named("forkedSpringBootRun", JavaExecFork::class)

Expand Down Expand Up @@ -102,15 +85,22 @@ class SpringDocOpenApiConfigurePlugin : Plugin<Project> {
val serverPort = freeServerSocketPort()
val managementPort = freeServerSocketPort()
val outputFileName = configureExtension.fileFormat.map { "${basename}.${it.extension}" }
val urlPrefix = "http://localhost:${serverPort}"
val docsUrl = openapi.outputFileName.map {
val basePath = "http://localhost:${serverPort}/v3/api-docs"
val basePath = "$urlPrefix/v3/api-docs"
when {
it.endsWith(".${OpenApiFormat.JSON.extension}") -> basePath
it.endsWith(".${OpenApiFormat.YAML.extension}") -> "${basePath}.${OpenApiFormat.YAML.extension}"
else -> throw UnsupportedFormatException("The provided openapi filename '${it}' ends in an unsupported extension. Make sure you use 'yaml' or 'json'")
}
}

openapi.groupedApiMappings.set(
configureExtension.groupedApiMappings.map { actualMap ->
actualMap.mapKeys { "$urlPrefix${it.key}" }
}
)

openapi.outputDir.set(target.layout.buildDirectory.dir("generated/resources/openapi"))
openapi.outputFileName.set(outputFileName)
openapi.apiDocsUrl.set(docsUrl)
Expand Down
37 changes: 37 additions & 0 deletions src/test/fixtures/springdocopenapi/grouped-api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/
26 changes: 26 additions & 0 deletions src/test/fixtures/springdocopenapi/grouped-api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
plugins {
id 'io.cloudflight.autoconfigure.springdoc-openapi-configure'
}

group = 'io.cloudflight.gradle'
version = '1.0.0'

repositories {
mavenCentral()
}

openApiConfigure {
groupedApiMappings = [
"/v3/api-docs/groupA": "groupA.yaml",
"/v3/api-docs/groupB": "groupB.yaml"
]
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.7.12'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.0'
}

tasks.named('test') {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'springdoc-openapi'
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.cloudflight.springdocopenapi;

import org.springdoc.core.GroupedOpenApi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class SpringDocOpenApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDocOpenApiApplication.class, args);
}
}

@RestController
class ControllerA {
@GetMapping("/a")
public String hello() {
return "hello";
}
}

@RestController
class ControllerB {
@GetMapping("/b")
public String hello() {
return "hello";
}
}

@Configuration
class SpringDocConfig {
@Bean
public GroupedOpenApi aApiGroup() {
String[] paths = {"/a"};
return GroupedOpenApi.builder()
.group("groupA")
.pathsToMatch(paths)
.build();
}

@Bean
public GroupedOpenApi bApiGroup() {
String[] paths = {"/b"};
return GroupedOpenApi.builder()
.group("groupB")
.pathsToMatch(paths)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public class SpringDocOpenApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDocOpenApiApplication.class, args);
}

}

@RestController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public class SpringDocOpenApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDocOpenApiApplication.class, args);
}

}

@RestController
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.cloudflight.gradle.autoconfigure.springdoc.openapi

import io.cloudflight.gradle.autoconfigure.test.util.ProjectFixture
import io.cloudflight.gradle.autoconfigure.test.util.normalizedOutput
import io.cloudflight.gradle.autoconfigure.test.util.useFixture
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
Expand All @@ -12,23 +11,32 @@ class SpringDocOpenApiConfigurePluginTest {
@Test
fun `the openapi document is created in a single module project with the default configuration`():
Unit = springdocFixture("simple") {
val result = run("clean", "clfGenerateOpenApiDocumentation")
run("clean", "clfGenerateOpenApiDocumentation")

assertThat(buildDir().resolve("generated/resources/openapi/springdoc-openapi.yaml")).exists()
}

@Test
fun `the openapi document is created in a single module project with the json configuration`():
Unit = springdocFixture("simple-json") {
val result = run("clean", "clfGenerateOpenApiDocumentation")
run("clean", "clfGenerateOpenApiDocumentation")

assertThat(buildDir().resolve("generated/resources/openapi/springdoc-openapi.json")).exists()
}

@Test
fun `the openapi documents are created in a single module project with grouped api configuration`():
Unit = springdocFixture("grouped-api") {
run("clean", "clfGenerateOpenApiDocumentation")

assertThat(buildDir().resolve("generated/resources/openapi/groupA.yaml")).exists()
assertThat(buildDir().resolve("generated/resources/openapi/groupB.yaml")).exists()
}

@Test
fun `the openapi document is created in a multi module project`():
Unit = springdocFixture("kotlin-springboot-angular") {
val result = run("clean", "publishToMavenLocal")
run("clean", "publishToMavenLocal")

assertThat(buildDir("skeleton-server").resolve("generated/resources/openapi/custom-openapi.json")).exists()
}
Expand Down

0 comments on commit 3252cfe

Please sign in to comment.