From f600a530e6dabee6d8590dbf2564556ff906d7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 2 Jun 2023 23:57:54 +0200 Subject: [PATCH 1/2] fix(spine-ktor): If the error format is invalid, try to parse it as a string --- .../src/commonMain/kotlin/Client.kt | 3 + .../src/commonTest/kotlin/FailureTest.kt | 92 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 spine-ktor/spine-ktor-server/src/commonTest/kotlin/FailureTest.kt diff --git a/spine-ktor/spine-ktor-client/src/commonMain/kotlin/Client.kt b/spine-ktor/spine-ktor-client/src/commonMain/kotlin/Client.kt index 27eaba9..225c8d6 100644 --- a/spine-ktor/spine-ktor-client/src/commonMain/kotlin/Client.kt +++ b/spine-ktor/spine-ktor-client/src/commonMain/kotlin/Client.kt @@ -5,6 +5,7 @@ import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* +import io.ktor.serialization.* import opensavvy.progress.coroutines.mapProgressTo import opensavvy.spine.Id import opensavvy.spine.Operation @@ -99,6 +100,8 @@ suspend inline fun ()) } catch (e: NoTransformationFoundException) { SpineFailure(kind, result.body().ifBlank { "${result.status} with no provided body" }) + } catch (e: JsonConvertException) { + SpineFailure(kind, result.body().ifBlank { "${result.status} with no provided body" }) } raise(failure) diff --git a/spine-ktor/spine-ktor-server/src/commonTest/kotlin/FailureTest.kt b/spine-ktor/spine-ktor-server/src/commonTest/kotlin/FailureTest.kt new file mode 100644 index 0000000..e26fe84 --- /dev/null +++ b/spine-ktor/spine-ktor-server/src/commonTest/kotlin/FailureTest.kt @@ -0,0 +1,92 @@ +package opensavvy.spine.ktor.server + +import io.ktor.client.plugins.logging.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.plugins.callloging.* +import io.ktor.server.testing.* +import kotlinx.serialization.Serializable +import opensavvy.spine.Parameters +import opensavvy.spine.Route +import opensavvy.spine.Route.Companion.div +import opensavvy.spine.Service +import opensavvy.spine.SpineFailure +import opensavvy.spine.ktor.client.request +import opensavvy.state.outcome.failed +import opensavvy.state.outcome.success +import org.junit.Test +import org.slf4j.event.Level +import kotlin.test.assertEquals +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation as ClientContentNegotiation +import io.ktor.server.plugins.contentnegotiation.ContentNegotiation as ServerContentNegotiation + +class FailureTest { + + @Serializable + private data class TestFailure(val a: Int) + + private class Api : Service("api") { + inner class Resource : StaticResource("resource") { + + val success = action(Route / "success") + val objectFailure = action(Route / "failWithObject") + val textFailure = action(Route / "failWithText") + + } + + val resource = Resource() + } + + @Test + fun test() = testApplication { + + val api = Api() + + install(ServerContentNegotiation) { + json() + } + + install(CallLogging) { + level = Level.DEBUG + } + + routing { + route(api.resource.success, { }) { + // Nothing to do + } + + route(api.resource.objectFailure, { }) { + raise(SpineFailure(SpineFailure.Type.InvalidRequest, TestFailure(5))) + } + + route(api.resource.textFailure, { }) { + raise(SpineFailure(SpineFailure.Type.InvalidRequest, "5")) + } + } + + val client = createClient { + install(ClientContentNegotiation) { + json() + } + + install(Logging) { + level = LogLevel.ALL + } + } + + assertEquals( + Unit.success(), + client.request(api.resource.success, api.resource.idOf(), Unit, Parameters.Empty, Unit), + ) + + assertEquals( + SpineFailure(SpineFailure.Type.InvalidRequest, TestFailure(5)).failed(), + client.request(api.resource.objectFailure, api.resource.idOf(), Unit, Parameters.Empty, Unit), + ) + + assertEquals( + SpineFailure(SpineFailure.Type.InvalidRequest, "5").failed(), + client.request(api.resource.textFailure, api.resource.idOf(), Unit, Parameters.Empty, Unit), + ) + } + +} -- 2.51.2 From 61ebecd3087d457bdaaf56551f935e84b78686d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 3 Jun 2023 00:32:59 +0200 Subject: [PATCH 2/2] fix(spine-ktor): A SpineFailure cannot have a 'null' payload --- spine-ktor/spine-ktor-server/src/commonMain/kotlin/Server.kt | 4 ++-- spine/src/commonMain/kotlin/SpineFailure.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spine-ktor/spine-ktor-server/src/commonMain/kotlin/Server.kt b/spine-ktor/spine-ktor-server/src/commonMain/kotlin/Server.kt index a4a6233..0e2bd7d 100644 --- a/spine-ktor/spine-ktor-server/src/commonMain/kotlin/Server.kt +++ b/spine-ktor/spine-ktor-server/src/commonMain/kotlin/Server.kt @@ -104,7 +104,7 @@ inline fun call.respond(it.type.toHttp(), it.message ?: "No message") - is SpineFailure.Payload -> call.respond(it.type.toHttp(), it.payload ?: "No message") + is SpineFailure.Payload -> call.respond(it.type.toHttp(), it.payload) } }, ifRight = { @@ -175,7 +175,7 @@ inline fun call.respond(it.type.toHttp(), it.message ?: "No message") - is SpineFailure.Payload -> call.respond(it.type.toHttp(), it.payload ?: "No message") + is SpineFailure.Payload -> call.respond(it.type.toHttp(), it.payload) } }, ifRight = { diff --git a/spine/src/commonMain/kotlin/SpineFailure.kt b/spine/src/commonMain/kotlin/SpineFailure.kt index 341ff93..a86205a 100644 --- a/spine/src/commonMain/kotlin/SpineFailure.kt +++ b/spine/src/commonMain/kotlin/SpineFailure.kt @@ -18,7 +18,7 @@ sealed class SpineFailure { data class Payload( override val type: Type, - override val payload: Payload?, + override val payload: Payload, ) : SpineFailure() { override fun toString() = "$type: “${payload}”" @@ -41,5 +41,5 @@ fun SpineFailure( fun SpineFailure( type: SpineFailure.Type, - payload: Payload?, + payload: Payload, ) = SpineFailure.Payload(type, payload) -- 2.51.2