From cc0b3c17e2cd1c17b9286af75c11b878fe73ac4e Mon Sep 17 00:00:00 2001 From: ccornu <ccornu@takima.fr> Date: Mon, 10 Feb 2025 19:06:12 +0100 Subject: [PATCH] feat: better exception handling --- build.gradle.kts | 13 +++++--- src/main/kotlin/Application.kt | 2 ++ .../configuration/ExceptionConfiguration.kt | 31 +++++++++++++++++++ src/main/kotlin/player/PlayerRoute.kt | 29 +++-------------- .../exceptions/AlreadyExistingException.kt | 2 +- 5 files changed, 46 insertions(+), 31 deletions(-) create mode 100644 src/main/kotlin/configuration/ExceptionConfiguration.kt diff --git a/build.gradle.kts b/build.gradle.kts index f445208..281e989 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ val koin_version: String by project val kotlin_version: String by project +val ktor_version: String by project val logback_version: String by project val dynamo_version: String by project val dynamo_kt_version: String by project @@ -32,11 +33,12 @@ repositories { dependencies { // Ktor - implementation("io.ktor:ktor-server-core") - implementation("io.ktor:ktor-server-auth") - implementation("io.ktor:ktor-server-openapi") - implementation("io.ktor:ktor-server-config-yaml") - implementation("io.ktor:ktor-server-netty") + implementation("io.ktor:ktor-server-core:$ktor_version") + implementation("io.ktor:ktor-server-auth:$ktor_version") + implementation("io.ktor:ktor-server-openapi:$ktor_version") + implementation("io.ktor:ktor-server-config-yaml:$ktor_version") + implementation("io.ktor:ktor-server-netty:$ktor_version") + implementation("io.ktor:ktor-server-status-pages:$ktor_version") // Dependency injection implementation("io.insert-koin:koin-ktor:$koin_version") @@ -52,6 +54,7 @@ dependencies { implementation("software.amazon.awssdk:dynamodb:$dynamo_version") implementation("dev.andrewohara:dynamokt:$dynamo_kt_version") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:$kotlin_reactive_version") + implementation("io.ktor:ktor-server-host-common:$ktor_version") // Tests testImplementation("io.ktor:ktor-server-test-host") diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt index 024521d..8814813 100644 --- a/src/main/kotlin/Application.kt +++ b/src/main/kotlin/Application.kt @@ -1,5 +1,6 @@ package betclic.test +import betclic.test.configuration.configureExceptionHandling import betclic.test.configuration.configureKoin import betclic.test.configuration.configureRouting import betclic.test.configuration.configureSerialization @@ -19,6 +20,7 @@ fun Application.module() { fun Application.configuration() { configureKoin() configureSerialization() + configureExceptionHandling() configureRouting() } diff --git a/src/main/kotlin/configuration/ExceptionConfiguration.kt b/src/main/kotlin/configuration/ExceptionConfiguration.kt new file mode 100644 index 0000000..c2a6274 --- /dev/null +++ b/src/main/kotlin/configuration/ExceptionConfiguration.kt @@ -0,0 +1,31 @@ +package betclic.test.configuration + +import betclic.test.player.exceptions.AlreadyExistingPlayerException +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.plugins.* +import io.ktor.server.plugins.statuspages.* +import io.ktor.server.response.* +import software.amazon.awssdk.services.dynamodb.model.DynamoDbException + +private const val SOMETHING_WENT_WRONG = "Something went wrong" + +fun Application.configureExceptionHandling() { + install(StatusPages) { + exception<Throwable> { call, cause -> + when (cause) { + is NotFoundException -> call.respond(HttpStatusCode.NotFound, cause.message ?: SOMETHING_WENT_WRONG) + is DynamoDbException -> call.respond( + HttpStatusCode.InternalServerError, + cause.message ?: "$SOMETHING_WENT_WRONG with DynamoDb" + ) + + is AlreadyExistingPlayerException -> call.respond( + HttpStatusCode.BadRequest, + cause.message ?: SOMETHING_WENT_WRONG + ) + } + call.respondText(text = "500: $cause", status = HttpStatusCode.InternalServerError) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/player/PlayerRoute.kt b/src/main/kotlin/player/PlayerRoute.kt index b52c4c3..439e37b 100644 --- a/src/main/kotlin/player/PlayerRoute.kt +++ b/src/main/kotlin/player/PlayerRoute.kt @@ -3,56 +3,35 @@ package betclic.test.player import betclic.test.player.dtos.PlayerCreationDTO import betclic.test.player.dtos.PlayerInfoDTO import betclic.test.player.dtos.PlayerUpdateDTO -import betclic.test.player.exceptions.AlreadyExistingPlayerException import io.ktor.http.* import io.ktor.server.application.* -import io.ktor.server.plugins.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import org.koin.ktor.ext.inject -private const val SOMETHING_WENT_WRONG = "Something went wrong." - fun Routing.playerRoutes() { val playerService by inject<PlayerService>() // const route("/players") { post { val request = call.receive<PlayerCreationDTO>() - try { - call.respond(HttpStatusCode.Created, playerService.createNewPlayer(request)) - } catch (e: AlreadyExistingPlayerException) { - call.respond(status = HttpStatusCode.BadRequest, message = e.message ?: SOMETHING_WENT_WRONG) - } + call.respond(HttpStatusCode.Created, playerService.createNewPlayer(request)) } put { val request = call.receive<PlayerUpdateDTO>() - try { - call.respond(HttpStatusCode.OK, playerService.updatePlayer(request)) - } catch (e: NotFoundException) { - call.respond(status = HttpStatusCode.NotFound, message = e.message ?: SOMETHING_WENT_WRONG) - } - + call.respond(HttpStatusCode.OK, playerService.updatePlayer(request)) } get("/{pseudo}") { val pseudo = call.parameters["pseudo"] ?: return@get call.respond(HttpStatusCode.BadRequest) - try { - call.respond<Player>(playerService.findPlayerByPseudo(pseudo)) - } catch (e: NotFoundException) { - call.respond(status = HttpStatusCode.NotFound, message = e.message ?: SOMETHING_WENT_WRONG) - } + call.respond<Player>(playerService.findPlayerByPseudo(pseudo)) } get("/{pseudo}/info") { val pseudo = call.parameters["pseudo"] ?: return@get call.respond(HttpStatusCode.BadRequest) - try { - call.respond<PlayerInfoDTO>(playerService.getPlayerInfoByPseudo(pseudo)) - } catch (e: NotFoundException) { - call.respond(status = HttpStatusCode.NotFound, message = e.message ?: SOMETHING_WENT_WRONG) - } + call.respond<PlayerInfoDTO>(playerService.getPlayerInfoByPseudo(pseudo)) } get("/ranking") { diff --git a/src/main/kotlin/player/exceptions/AlreadyExistingException.kt b/src/main/kotlin/player/exceptions/AlreadyExistingException.kt index 4deded5..f08bc6f 100644 --- a/src/main/kotlin/player/exceptions/AlreadyExistingException.kt +++ b/src/main/kotlin/player/exceptions/AlreadyExistingException.kt @@ -1,4 +1,4 @@ package betclic.test.player.exceptions class AlreadyExistingPlayerException(val pseudo: String) : - RuntimeException("$pseudo already exists. You still can update this player points") \ No newline at end of file + Exception("$pseudo already exists. You still can update this player points") \ No newline at end of file -- GitLab