From 24aa9798486dc8c3c9858bfe5cf9db1892c4f19c Mon Sep 17 00:00:00 2001 From: Lukas Ruegner Date: Sat, 11 Jan 2025 15:39:00 +0100 Subject: [PATCH] fix multipart schema / file upload --- .../ktorswaggerui/examples/CompleteConfig.kt | 5 ++-- .../ktorswaggerui/examples/FileUpload.kt | 23 +++++++++++++++++-- .../smiley4/ktorswaggerui/examples/Schemas.kt | 4 ++-- .../builder/openapi/ContentBuilder.kt | 2 +- .../builder/OperationBuilderTest.kt | 4 ++-- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteConfig.kt b/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteConfig.kt index 16e17535..149e5d1b 100644 --- a/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteConfig.kt +++ b/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteConfig.kt @@ -14,6 +14,7 @@ import io.github.smiley4.schemakenerator.swagger.compileReferencingRoot import io.github.smiley4.schemakenerator.swagger.data.TitleType import io.github.smiley4.schemakenerator.swagger.generateSwaggerSchema import io.github.smiley4.schemakenerator.swagger.withAutoTitle +import io.github.smiley4.schemakenerator.swagger.withTitle import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode import io.ktor.server.application.Application @@ -116,11 +117,11 @@ private fun Application.myModule() { type .processReflection() .generateSwaggerSchema() - .withAutoTitle(TitleType.SIMPLE) + .withTitle(TitleType.SIMPLE) .compileReferencingRoot() } overwrite(Schema().also { - it.type = "string" + it.types = setOf("string") it.format = "binary" }) } diff --git a/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/FileUpload.kt b/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/FileUpload.kt index 189adae8..ac658da9 100644 --- a/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/FileUpload.kt +++ b/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/FileUpload.kt @@ -1,6 +1,7 @@ package io.github.smiley4.ktorswaggerui.examples import io.github.smiley4.ktorswaggerui.SwaggerUI +import io.github.smiley4.ktorswaggerui.data.array import io.github.smiley4.ktorswaggerui.dsl.routing.post import io.github.smiley4.ktorswaggerui.routing.openApiSpec import io.github.smiley4.ktorswaggerui.routing.swaggerUI @@ -28,7 +29,7 @@ private fun Application.myModule() { schemas { // overwrite type "File" with custom schema for binary data overwrite(Schema().also { - it.type = "string" + it.types = setOf("string") it.format = "binary" }) } @@ -59,7 +60,7 @@ private fun Application.myModule() { call.respond(HttpStatusCode.NotImplemented, "...") } - // upload multiple files + // upload multiple (two) files post("multipart", { request { multipartBody { @@ -84,6 +85,24 @@ private fun Application.myModule() { call.respond(HttpStatusCode.NotImplemented, "...") } + // upload multiple (any amount of) files + post("list", { + request { + multipartBody { + mediaTypes(ContentType.MultiPart.FormData) + part("images", array()) { + mediaTypes( + ContentType.Image.PNG, + ContentType.Image.JPEG, + ContentType.Image.SVG + ) + } + } + } + }) { + call.respond(HttpStatusCode.NotImplemented, "...") + } + } } diff --git a/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/Schemas.kt b/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/Schemas.kt index b078b9af..0ce9fe0d 100644 --- a/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/Schemas.kt +++ b/ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples/Schemas.kt @@ -38,7 +38,7 @@ private fun Application.myModule() { // add a swagger schema to the component-section of the api-spec with the id "swagger-schema" schema("swagger-schema", Schema().also { - it.type = "number" + it.types = setOf("number") it.title = "Custom Type" }) @@ -48,7 +48,7 @@ private fun Application.myModule() { // overwrite 'LocalDateTime' with custom schema (root only) overwrite(Schema().also { it.title = "timestamp" - it.type = "integer" + it.types = setOf("integer") }) // customized schema generation pipeline diff --git a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt index fc2e213e..44af0a8f 100644 --- a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt +++ b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt @@ -66,7 +66,7 @@ class ContentBuilder( private fun buildMultipartMediaType(body: OpenApiMultipartBodyData): MediaType { return MediaType().also { mediaType -> mediaType.schema = Schema().also { schema -> - schema.type = "object" + schema.types = setOf("object") schema.properties = mutableMapOf?>().also { props -> body.parts.forEach { part -> props[part.name] = schemaContext.getSchema(part.type) diff --git a/ktor-swagger-ui/src/test/kotlin/io/github/smiley4/ktorswaggerui/builder/OperationBuilderTest.kt b/ktor-swagger-ui/src/test/kotlin/io/github/smiley4/ktorswaggerui/builder/OperationBuilderTest.kt index ef51e82a..7b6fa978 100644 --- a/ktor-swagger-ui/src/test/kotlin/io/github/smiley4/ktorswaggerui/builder/OperationBuilderTest.kt +++ b/ktor-swagger-ui/src/test/kotlin/io/github/smiley4/ktorswaggerui/builder/OperationBuilderTest.kt @@ -559,7 +559,7 @@ class OperationBuilderTest : StringSpec({ mediaType.schema .also { it.shouldNotBeNull() } ?.also { schema -> - schema.type shouldBe "object" + schema.types shouldContainExactlyInAnyOrder listOf("object") schema.properties.keys shouldContainExactlyInAnyOrder listOf( "image", "data" @@ -961,7 +961,7 @@ class OperationBuilderTest : StringSpec({ mediaType.schema .also { it.shouldNotBeNull() } ?.also { schema -> - schema.type shouldBe "object" + schema.types shouldContainExactlyInAnyOrder listOf("object") schema.properties.keys shouldContainExactlyInAnyOrder listOf("customData") schema.properties["customData"]!!.`$ref` shouldBe "#/components/schemas/myCustomSchema" }