diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt new file mode 100644 index 0000000..fa07ba1 --- /dev/null +++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/Response.kt @@ -0,0 +1,6 @@ +package com.github.alice.ktx.api.common + +sealed interface Response{ + data class Failed(val message: String): Response + data class Success(val data: T): Response +} \ No newline at end of file diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt new file mode 100644 index 0000000..deb078e --- /dev/null +++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/common/extensions/ResponseExtensions.kt @@ -0,0 +1,13 @@ +package com.github.alice.ktx.api.common.extensions + +import com.github.alice.ktx.api.common.Response +import com.github.alice.ktx.api.dialog.yandex.models.ErrorBody +import io.ktor.client.call.* +import io.ktor.client.statement.* + +suspend inline fun HttpResponse.response(): Response { + return if(status.value in 200..299) + Response.Success(this.body()) + else + Response.Failed(this.body().message) +} \ No newline at end of file diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/DialogApi.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/DialogApi.kt index 7754513..4f874bd 100644 --- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/DialogApi.kt +++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/DialogApi.kt @@ -1,14 +1,15 @@ package com.github.alice.ktx.api.dialog +import com.github.alice.ktx.api.common.Response import com.github.alice.ktx.api.dialog.yandex.models.image.response.ImageUpload import com.github.alice.ktx.api.dialog.yandex.models.image.response.Images import com.github.alice.ktx.api.dialog.yandex.models.status.Status import java.io.File interface DialogApi { - suspend fun getStatus(): Status - suspend fun uploadImage(url: String): ImageUpload - suspend fun uploadImage(file: File): ImageUpload - suspend fun getAllImages(): Images - suspend fun deleteImage(id: String): Boolean + suspend fun getStatus(): Response + suspend fun uploadImage(url: String): Response + suspend fun uploadImage(file: File): Response + suspend fun getAllImages(): Response + suspend fun deleteImage(id: String): Response } \ No newline at end of file diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt index 2d063eb..eb07f6a 100644 --- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt +++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/impl/KtorYandexDialogApi.kt @@ -1,7 +1,10 @@ package com.github.alice.ktx.api.dialog.yandex.impl import com.github.alice.ktx.Skill +import com.github.alice.ktx.api.common.Response +import com.github.alice.ktx.api.common.extensions.response import com.github.alice.ktx.api.dialog.DialogApi +import com.github.alice.ktx.api.dialog.yandex.models.ErrorBody import com.github.alice.ktx.api.dialog.yandex.models.image.request.ImageUploadUrl import com.github.alice.ktx.api.dialog.yandex.models.image.response.DeleteImage import com.github.alice.ktx.api.dialog.yandex.models.image.response.ImageUpload @@ -14,6 +17,7 @@ import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.client.request.forms.* +import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import io.ktor.util.* @@ -58,19 +62,19 @@ class KtorYandexDialogApi( } } - override suspend fun getStatus(): Status { - return client.get("api/v1/status").body() + override suspend fun getStatus(): Response { + return client.get("api/v1/status").response() } - override suspend fun uploadImage(url: String): ImageUpload { + override suspend fun uploadImage(url: String): Response { val body = ImageUploadUrl(url = url) return client.post("api/v1/skills/$skillId/images") { contentType(ContentType.Application.Json) setBody(body) - }.body() + }.response() } - override suspend fun uploadImage(file: File): ImageUpload { + override suspend fun uploadImage(file: File): Response { return client.submitFormWithBinaryData( url = "api/v1/skills/$skillId/images", formData = formData { @@ -79,15 +83,14 @@ class KtorYandexDialogApi( append(HttpHeaders.ContentDisposition, "filename=\"${file.name}\"") }) } - ).body() + ).response() } - override suspend fun getAllImages(): Images { - return client.get("api/v1/skills/$skillId/images").body() + override suspend fun getAllImages(): Response { + return client.get("api/v1/skills/$skillId/images").response() } - override suspend fun deleteImage(id: String): Boolean { - val response = client.delete("api/v1/skills/$skillId/images/$id") - return response.status == HttpStatusCode.OK && response.body().result == SUCCESS_MESSAGE + override suspend fun deleteImage(id: String): Response { + return client.delete("api/v1/skills/$skillId/images/$id").response() } } \ No newline at end of file diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/ErrorBody.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/ErrorBody.kt new file mode 100644 index 0000000..5c7c46a --- /dev/null +++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/api/dialog/yandex/models/ErrorBody.kt @@ -0,0 +1,8 @@ +package com.github.alice.ktx.api.dialog.yandex.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ErrorBody( + val message: String +) diff --git a/alice-ktx/src/main/kotlin/com/github/alice/ktx/server/impl/KtorWebServer.kt b/alice-ktx/src/main/kotlin/com/github/alice/ktx/server/impl/KtorWebServer.kt index 315b73f..31fe876 100644 --- a/alice-ktx/src/main/kotlin/com/github/alice/ktx/server/impl/KtorWebServer.kt +++ b/alice-ktx/src/main/kotlin/com/github/alice/ktx/server/impl/KtorWebServer.kt @@ -78,7 +78,9 @@ class KtorWebServer( }catch (e: Throwable) { listener.responseFailure(model, e)?.let { response -> call.respond(response) + return@post } + throw e } } } diff --git a/examples/src/main/kotlin/com/github/examples/ImageDialogsApi.kt b/examples/src/main/kotlin/com/github/examples/ImageDialogsApi.kt index f98477a..223bbc9 100644 --- a/examples/src/main/kotlin/com/github/examples/ImageDialogsApi.kt +++ b/examples/src/main/kotlin/com/github/examples/ImageDialogsApi.kt @@ -1,6 +1,7 @@ package com.github.examples import com.github.alice.ktx.Dispatcher +import com.github.alice.ktx.api.common.Response import com.github.alice.ktx.api.dialog.yandex.impl.ktorYandexDialogApi import com.github.alice.ktx.dispatch import com.github.alice.ktx.handlers.message @@ -27,17 +28,21 @@ fun main() { message({ message.request.payload?.keys?.contains("delete_image_id") == true }) { val imageId = message.request.payload!!["delete_image_id"].toString() - val result = dialogApi?.deleteImage(imageId) ?: false + val result = dialogApi?.deleteImage(imageId) response { - text = if(result) "Success" else "Failure" + text = if(result is Response.Success) "Success" else "Failure" } } message({ message.request.originalUtterance == "upload_image_file" }) { val file = File("ktor_icon.png") - val result = dialogApi?.uploadImage(file) + val response = dialogApi?.uploadImage(file) response { - text = result?.image.toString() + text = when(response) { + is Response.Failed -> response.message + is Response.Success -> response.data.image.toString() + null -> throw NullPointerException("Response was null") + } } } } @@ -47,15 +52,20 @@ fun main() { private fun Dispatcher.messageCardImages() { message({ message.session.new }) { val imageResponse = dialogApi?.getAllImages() - response { - cardItemsList { - header = "Images (${imageResponse?.total})" - imageResponse?.images?.forEach { image -> - item { - imageId = image.id - mediaButton { - text = "Delete" - payload = mapOf("delete_image_id" to image.id) + when(imageResponse) { + is Response.Failed, null -> response { + text = "Failed" + } + is Response.Success -> response { + cardItemsList { + header = "Images (${imageResponse.data.total})" + imageResponse.data.images.forEach { image -> + item { + imageId = image.id + mediaButton { + text = "Delete" + payload = mapOf("delete_image_id" to image.id) + } } } }