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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ openapi { //6
basePath = '/api'
title = 'My API'
description = 'My API description'
tagDescriptionsPropertiesFile = 'src/docs/tag-descriptions.yaml'
version = '1.0.0'
format = 'json'
}
Expand All @@ -116,6 +117,7 @@ openapi3 {
server = 'https://localhost:8080'
title = 'My API'
description = 'My API description'
tagDescriptionsPropertiesFile = 'src/docs/tag-descriptions.yaml'
version = '0.1.0'
format = 'yaml'
}
Expand Down Expand Up @@ -334,6 +336,7 @@ title | The title of the application. Used for the `title` attribute in the [Inf
description | A description of the application. Used for the `description` attribute in the [Info object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#info-object) | empty
version | The version of the api. Used for the `version` attribute in the [Info object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#info-object) | project version
format | The format of the output OpenAPI file - supported values are `json` and `yaml` | `json`
tagDescriptionsPropertiesFile | A yaml file mapping tag names to descriptions. These are populated into the top level ` [Tags attribute](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#tag-object) | no default - if not provided no tags created.
separatePublicApi | Should the plugin generate an additional OpenAPI specification file that does not contain the resources marked as private | `false`
outputDirectory | The output directory | `build/openapi`
snippetsDirectory | The directory Spring REST Docs generated the snippets to | `build/generated-snippets`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ open class OpenApi3Task : OpenApiBaseTask() {
servers = servers,
title = title,
description = apiDescription,
tagDescriptions = tagDescriptions,
version = apiVersion,
oauth2SecuritySchemeDefinition = oauth2SecuritySchemeDefinition,
format = format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ abstract class OpenApiBaseTask : ApiSpecTask() {
@Optional
lateinit var format: String

@Input
@Optional
lateinit var tagDescriptions: Map<String, String>

@Input @Optional
var oauth2SecuritySchemeDefinition: PluginOauth2Configuration? = null

Expand All @@ -31,6 +35,7 @@ abstract class OpenApiBaseTask : ApiSpecTask() {
oauth2SecuritySchemeDefinition = extension.oauth2SecuritySchemeDefinition
title = extension.title
apiDescription = extension.description
tagDescriptions = extension.tagDescriptions()
apiVersion = extension.version
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ abstract class OpenApiBaseExtension(project: Project) : ApiSpecExtension(project
var title = "API documentation"
var version = project.version as? String ?: "1.0.0"
var description: String? = null
var tagDescriptionsPropertiesFile: String? = null

var format = "json"

Expand All @@ -31,6 +32,10 @@ abstract class OpenApiBaseExtension(project: Project) : ApiSpecExtension(project
}
}

fun tagDescriptions(): Map<String, String> {
return tagDescriptionsPropertiesFile?.let { objectMapper.readValue(project.file(it)) } ?: emptyMap()
}

private fun scopeDescriptionSource(scopeDescriptionsPropertiesFile: File): Map<String, String> {
return scopeDescriptionsPropertiesFile.let { objectMapper.readValue<Map<String, String>>(it) } ?: emptyMap()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ open class OpenApiTask : OpenApiBaseTask() {
schemes = schemes.toList(),
title = title,
description = apiDescription,
tagDescriptions = tagDescriptions,
version = apiVersion,
oauth2SecuritySchemeDefinition = oauth2SecuritySchemeDefinition,
format = format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class RestdocsOpenApi3TaskTest : RestdocsOpenApiTaskTestBase() {
servers = [ { url = "http://some.api" } ]
title = '$title'
description = '$description'
tagDescriptionsPropertiesFile = "tagDescriptions.yaml"
version = '$version'
format = '$format'
separatePublicApi = $separatePublicApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class RestdocsOpenApiTaskTest : RestdocsOpenApiTaskTestBase() {
schemes = ${schemes.joinToString(",", "['", "']")}
title = '$title'
description = '$description'
tagDescriptionsPropertiesFile = "tagDescriptions.yaml"
version = '$version'
format = '$format'
separatePublicApi = $separatePublicApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ abstract class RestdocsOpenApiTaskTestBase {
@Test
open fun `should run openapi task`() {
givenBuildFileWithOpenApiClosure()
givenTagsTextFile()
givenResourceSnippet()

whenPluginExecuted()
Expand All @@ -80,6 +81,7 @@ abstract class RestdocsOpenApiTaskTestBase {
fun `should run openapi task with yaml format`() {
format = "yaml"
givenBuildFileWithOpenApiClosure()
givenTagsTextFile()
givenResourceSnippet()

whenPluginExecuted()
Expand All @@ -92,6 +94,7 @@ abstract class RestdocsOpenApiTaskTestBase {
fun `should generate separate public api specification`() {
separatePublicApi = true
givenBuildFileWithOpenApiClosure()
givenTagsTextFile()
givenResourceSnippet()
givenPrivateResourceSnippet()

Expand All @@ -105,6 +108,7 @@ abstract class RestdocsOpenApiTaskTestBase {
@Test
fun `should consider security definitions`() {
givenBuildFileWithOpenApiClosureAndSecurityDefinitions()
givenTagsTextFile()
givenResourceSnippet()
givenScopeTextFile()

Expand All @@ -124,7 +128,14 @@ abstract class RestdocsOpenApiTaskTestBase {
""".trimIndent()
)
}

private fun givenTagsTextFile() {
testProjectDir.resolve("tagDescriptions.yaml").toFile().writeText(
"""
"tag1": "tag1 description"
"tag2": "tag2 description"
""".trimIndent()
)
}
protected fun thenOpenApiTaskSuccessful() {
then(result.task(":$taskName")!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.swagger.models.RefModel
import io.swagger.models.Response
import io.swagger.models.Scheme
import io.swagger.models.Swagger
import io.swagger.models.Tag
import io.swagger.models.auth.ApiKeyAuthDefinition
import io.swagger.models.auth.BasicAuthDefinition
import io.swagger.models.auth.OAuth2Definition
Expand All @@ -44,6 +45,7 @@ object OpenApi20Generator {
schemes: List<String> = listOf("http"),
title: String = "API",
description: String? = null,
tagDescriptions: Map<String, String> = emptyMap(),
version: String = "1.0.0",
oauth2SecuritySchemeDefinition: Oauth2Configuration? = null
): Swagger {
Expand All @@ -57,6 +59,10 @@ object OpenApi20Generator {
this.description = description
this.version = version
}
this.tags(tagDescriptions.map { Tag().apply {
this.name = it.key
this.description = it.value
} })
paths = generatePaths(
resources,
oauth2SecuritySchemeDefinition
Expand All @@ -78,11 +84,12 @@ object OpenApi20Generator {
schemes: List<String> = listOf("http"),
title: String = "API",
description: String? = null,
tagDescriptions: Map<String, String> = emptyMap(),
version: String = "1.0.0",
oauth2SecuritySchemeDefinition: Oauth2Configuration? = null,
format: String
): String {
val specification = generate(resources, basePath, host, schemes, title, description, version, oauth2SecuritySchemeDefinition)
val specification = generate(resources, basePath, host, schemes, title, description, tagDescriptions, version, oauth2SecuritySchemeDefinition)
return ApiSpecificationWriter.serialize(format, specification)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,29 @@ import io.swagger.models.parameters.Parameter
import io.swagger.models.parameters.PathParameter
import io.swagger.parser.Swagger20Parser
import io.swagger.util.Json
import org.assertj.core.api.Assertions.tuple
import org.assertj.core.api.BDDAssertions.then
import org.junit.jupiter.api.Test

private const val SCHEMA_JSONPATH_PREFIX = "#/definitions/"

class OpenApi20GeneratorTest {

@Test
fun `should have parent tags generated for openapi`() {
val api = givenGetProductResourceModel()

val openapi = whenOpenApiObjectGenerated(api)

with(openapi) {
then(this.tags).extracting("name", "description")
.containsExactly(
tuple("tag1", "tag1 description"),
tuple("tag2", "tag2 description")
)
}
}

@Test
fun `should convert single resource model to openapi`() {
val api = givenGetProductResourceModel()
Expand Down Expand Up @@ -143,7 +159,8 @@ class OpenApi20GeneratorTest {
"http://example.com/authorize",
arrayOf("application", "accessCode")
),
description = "API description"
description = "API description",
tagDescriptions = mapOf("tag1" to "tag1 description", "tag2" to "tag2 description")
)

println(ApiSpecificationWriter.serialize("yaml", openapi))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import io.swagger.v3.oas.models.parameters.RequestBody
import io.swagger.v3.oas.models.responses.ApiResponse
import io.swagger.v3.oas.models.responses.ApiResponses
import io.swagger.v3.oas.models.servers.Server
import io.swagger.v3.oas.models.tags.Tag
import java.util.Comparator.comparing
import java.util.Comparator.comparingInt

Expand All @@ -46,6 +47,7 @@ object OpenApi3Generator {
servers: List<Server>,
title: String = "API",
description: String? = null,
tagDescriptions: Map<String, String> = emptyMap(),
version: String = "1.0.0",
oauth2SecuritySchemeDefinition: Oauth2Configuration? = null
): OpenAPI {
Expand All @@ -57,6 +59,10 @@ object OpenApi3Generator {
this.description = description
this.version = version
}
this.tags(tagDescriptions.map { Tag().apply {
this.name = it.key
this.description = it.value
} })
paths = generatePaths(
resources,
oauth2SecuritySchemeDefinition
Expand All @@ -71,6 +77,7 @@ object OpenApi3Generator {
servers: List<Server>,
title: String = "API",
description: String? = null,
tagDescriptions: Map<String, String> = emptyMap(),
version: String = "1.0.0",
oauth2SecuritySchemeDefinition: Oauth2Configuration? = null,
format: String
Expand All @@ -81,6 +88,7 @@ object OpenApi3Generator {
servers = servers,
title = title,
description = description,
tagDescriptions = tagDescriptions,
version = version,
oauth2SecuritySchemeDefinition = oauth2SecuritySchemeDefinition
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class OpenApi3GeneratorTest {
thenGetProductByIdOperationIsValid()
thenSecuritySchemesPresent()
thenInfoFieldsPresent()
thenTagFieldsPresent()
thenServersPresent()
thenOpenApiSpecIsValid()
}
Expand Down Expand Up @@ -156,6 +157,13 @@ class OpenApi3GeneratorTest {
then(openApiJsonPathContext.read<String>("info.version")).isEqualTo("1.0.0")
}

private fun thenTagFieldsPresent() {
then(openApiJsonPathContext.read<String>("tags[0].name")).isEqualTo("tag1")
then(openApiJsonPathContext.read<String>("tags[0].description")).isEqualTo("tag1 description")
then(openApiJsonPathContext.read<String>("tags[1].name")).isEqualTo("tag2")
then(openApiJsonPathContext.read<String>("tags[1].description")).isEqualTo("tag2 description")
}

private fun thenSecuritySchemesPresent() {
then(openApiJsonPathContext.read<String>("components.securitySchemes.oauth2.type")).isEqualTo("oauth2")
then(openApiJsonPathContext.read<Map<String, Any>>("components.securitySchemes.oauth2.flows"))
Expand All @@ -176,7 +184,8 @@ class OpenApi3GeneratorTest {
arrayOf("clientCredentials", "authorizationCode")
),
format = "json",
description = "API Description"
description = "API Description",
tagDescriptions = mapOf("tag1" to "tag1 description", "tag2" to "tag2 description")
)

println(openApiSpecJsonString)
Expand Down