diff --git a/core/src/main/kotlin/com/avsystem/justworks/core/gen/Names.kt b/core/src/main/kotlin/com/avsystem/justworks/core/gen/Names.kt index a2a3b24..0b40277 100644 --- a/core/src/main/kotlin/com/avsystem/justworks/core/gen/Names.kt +++ b/core/src/main/kotlin/com/avsystem/justworks/core/gen/Names.kt @@ -23,6 +23,9 @@ val POST_FUN = MemberName("io.ktor.client.request", "post") val PUT_FUN = MemberName("io.ktor.client.request", "put") val DELETE_FUN = MemberName("io.ktor.client.request", "delete") val PATCH_FUN = MemberName("io.ktor.client.request", "patch") +val HEAD_FUN = MemberName("io.ktor.client.request", "head") +val OPTIONS_FUN = MemberName("io.ktor.client.request", "options") +val REQUEST_FUN = MemberName("io.ktor.client.request", "request") // ============================================================================ // Ktor Forms & Multipart diff --git a/core/src/main/kotlin/com/avsystem/justworks/core/gen/client/BodyGenerator.kt b/core/src/main/kotlin/com/avsystem/justworks/core/gen/client/BodyGenerator.kt index 85bbe6f..0eb9952 100644 --- a/core/src/main/kotlin/com/avsystem/justworks/core/gen/client/BodyGenerator.kt +++ b/core/src/main/kotlin/com/avsystem/justworks/core/gen/client/BodyGenerator.kt @@ -12,12 +12,15 @@ import com.avsystem.justworks.core.gen.FORM_DATA_FUN import com.avsystem.justworks.core.gen.GET_FUN import com.avsystem.justworks.core.gen.HEADERS_CLASS import com.avsystem.justworks.core.gen.HEADERS_FUN +import com.avsystem.justworks.core.gen.HEAD_FUN import com.avsystem.justworks.core.gen.HTTP_HEADERS import com.avsystem.justworks.core.gen.HTTP_METHOD_CLASS +import com.avsystem.justworks.core.gen.OPTIONS_FUN import com.avsystem.justworks.core.gen.PARAMETERS_FUN import com.avsystem.justworks.core.gen.PATCH_FUN import com.avsystem.justworks.core.gen.POST_FUN import com.avsystem.justworks.core.gen.PUT_FUN +import com.avsystem.justworks.core.gen.REQUEST_FUN import com.avsystem.justworks.core.gen.SAFE_CALL import com.avsystem.justworks.core.gen.SET_BODY_FUN import com.avsystem.justworks.core.gen.SUBMIT_FORM_FUN @@ -77,9 +80,15 @@ internal object BodyGenerator { HttpMethod.PUT -> PUT_FUN HttpMethod.DELETE -> DELETE_FUN HttpMethod.PATCH -> PATCH_FUN + HttpMethod.HEAD -> HEAD_FUN + HttpMethod.OPTIONS -> OPTIONS_FUN + HttpMethod.TRACE -> REQUEST_FUN } beginControlFlow("$CLIENT.%M(%L)", httpMethodFun, urlString) + if (endpoint.method == HttpMethod.TRACE) { + addStatement("method = %T(%S)", HTTP_METHOD_CLASS, "TRACE") + } addCommonRequestParts(params) if (endpoint.requestBody != null) { @@ -193,7 +202,11 @@ internal object BodyGenerator { private fun CodeBlock.Builder.addHttpMethodIfNeeded(method: HttpMethod) { if (method != HttpMethod.POST) { - addStatement("method = %T.%L", HTTP_METHOD_CLASS, method.name.toPascalCase()) + if (method == HttpMethod.TRACE) { + addStatement("method = %T(%S)", HTTP_METHOD_CLASS, "TRACE") + } else { + addStatement("method = %T.%L", HTTP_METHOD_CLASS, method.name.toPascalCase()) + } } } diff --git a/core/src/main/kotlin/com/avsystem/justworks/core/model/ApiSpec.kt b/core/src/main/kotlin/com/avsystem/justworks/core/model/ApiSpec.kt index dc5d0ef..dba29e8 100644 --- a/core/src/main/kotlin/com/avsystem/justworks/core/model/ApiSpec.kt +++ b/core/src/main/kotlin/com/avsystem/justworks/core/model/ApiSpec.kt @@ -49,7 +49,10 @@ enum class HttpMethod { POST, PUT, DELETE, - PATCH + PATCH, + HEAD, + OPTIONS, + TRACE } data class Parameter( diff --git a/core/src/test/kotlin/com/avsystem/justworks/core/gen/ClientGeneratorTest.kt b/core/src/test/kotlin/com/avsystem/justworks/core/gen/ClientGeneratorTest.kt index efb0094..3a5fc2a 100644 --- a/core/src/test/kotlin/com/avsystem/justworks/core/gen/ClientGeneratorTest.kt +++ b/core/src/test/kotlin/com/avsystem/justworks/core/gen/ClientGeneratorTest.kt @@ -126,6 +126,9 @@ class ClientGeneratorTest { HttpMethod.PUT to "updatePet", HttpMethod.DELETE to "deletePet", HttpMethod.PATCH to "patchPet", + HttpMethod.HEAD to "headPet", + HttpMethod.OPTIONS to "optionsPet", + HttpMethod.TRACE to "tracePet", ) val endpoints = methods.map { (method, opId) -> endpoint(method = method, operationId = opId) }.toTypedArray() val cls = clientClass(*endpoints) @@ -151,6 +154,24 @@ class ClientGeneratorTest { funBodies["patchPet"]!!.contains("request.patch(") || funBodies["patchPet"]!!.contains("request.`patch`("), "PATCH method expected", ) + assertTrue( + funBodies["headPet"]!!.contains("request.head(") || funBodies["headPet"]!!.contains("request.`head`("), + "HEAD method expected", + ) + assertTrue( + funBodies["optionsPet"]!!.contains("request.options(") || + funBodies["optionsPet"]!!.contains("request.`options`("), + "OPTIONS method expected", + ) + assertTrue( + funBodies["tracePet"]!!.contains("request.request(") || + funBodies["tracePet"]!!.contains("request.`request`("), + "TRACE method expected (via request builder)", + ) + assertTrue( + funBodies["tracePet"]!!.contains("HttpMethod(\"TRACE\")"), + "TRACE should set explicit HttpMethod", + ) } // -- CLNT-04: Path parameters become function parameters -- diff --git a/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt b/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt index ad055d5..199c423 100644 --- a/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt +++ b/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt @@ -160,6 +160,45 @@ class SpecParserTest : SpecParserTestBase() { assertEquals("Pet", itemType.schemaName) } + // -- SPEC-01b: HEAD, OPTIONS, TRACE parsing -- + + @Test + fun `parse spec with HEAD, OPTIONS and TRACE methods`() { + val spec = parseSpec( + """ + openapi: 3.0.0 + info: + title: Test + version: 1.0.0 + paths: + /health: + head: + operationId: healthHead + tags: [Health] + responses: + '200': + description: OK + options: + operationId: healthOptions + tags: [Health] + responses: + '200': + description: OK + trace: + operationId: healthTrace + tags: [Health] + responses: + '200': + description: OK + """.trimIndent().toTempFile(), + ) + + assertEquals(3, spec.endpoints.size) + assertEquals(HttpMethod.HEAD, spec.endpoints.find { it.operationId == "healthHead" }?.method) + assertEquals(HttpMethod.OPTIONS, spec.endpoints.find { it.operationId == "healthOptions" }?.method) + assertEquals(HttpMethod.TRACE, spec.endpoints.find { it.operationId == "healthTrace" }?.method) + } + // -- SPEC-02: $ref resolution -- @Test