From 93bd094823cb1808eb35ecd6a71f518031b6c158 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 14 Aug 2020 12:06:37 +0600 Subject: [PATCH 1/3] add server realization of post repos --- .../core/content/api/ReadContentRepo.kt | 2 +- .../core/exposed/ExposedContentRepo.kt | 2 +- .../client/content/ContentRepoKtorClient.kt | 33 ++++++---- .../content/ReadContentRepoKtorClient.kt | 2 +- .../postssystem/core/ktor/ContentRoutes.kt | 2 + .../content/ContentRepoRoutingConfigurator.kt | 26 ++++++++ .../ReadContentRepoRoutingConfigurator.kt | 55 ++++++++++++++++ .../WriteContentRepoRoutingConfigurator.kt | 63 +++++++++++++++++++ .../ktor/server/PaginationInUrl.kt | 10 +++ .../ApplicationRoutingConfigurator.kt | 3 +- .../standardKtorSerialFormatContentType.kt | 5 ++ 11 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ContentRepoRoutingConfigurator.kt create mode 100644 core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt create mode 100644 core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/PaginationInUrl.kt create mode 100644 ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/standardKtorSerialFormatContentType.kt diff --git a/core/api/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/content/api/ReadContentRepo.kt b/core/api/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/content/api/ReadContentRepo.kt index d17e3817..cbca2611 100644 --- a/core/api/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/content/api/ReadContentRepo.kt +++ b/core/api/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/content/api/ReadContentRepo.kt @@ -21,5 +21,5 @@ interface ReadContentRepo { /** * @return all [RegisteredContent] by pages basing on their creation date */ - suspend fun getContentByPagination(pagination: Pagination): PaginationResult + suspend fun getContentByPagination(pagination: Pagination): PaginationResult } \ No newline at end of file diff --git a/core/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/core/exposed/ExposedContentRepo.kt b/core/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/core/exposed/ExposedContentRepo.kt index e941308a..343093b0 100644 --- a/core/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/core/exposed/ExposedContentRepo.kt +++ b/core/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/core/exposed/ExposedContentRepo.kt @@ -131,7 +131,7 @@ private class ContentRepoDatabaseTable( select { idColumn.eq(id) }.limit(1).firstOrNull() ?.asRegisteredContent(content) } } - override suspend fun getContentByPagination(pagination: Pagination): PaginationResult { + override suspend fun getContentByPagination(pagination: Pagination): PaginationResult { return transaction( db = database ) { diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ContentRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ContentRepoKtorClient.kt index b644855b..f1498a92 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ContentRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ContentRepoKtorClient.kt @@ -1,18 +1,27 @@ package com.insanusmokrassar.postssystem.core.ktor.client.content import com.insanusmokrassar.postssystem.core.content.api.* +import com.insanusmokrassar.postssystem.core.ktor.contentRootRoute import io.ktor.client.HttpClient import io.ktor.client.features.websocket.WebSockets -class ContentRepoKtorClient( - baseUrl: String, - client: HttpClient = HttpClient { - install(WebSockets) - } -) : ContentRepo, ReadContentRepo by ReadContentRepoKtorClient( - baseUrl, - client -), WriteContentRepo by WriteContentRepoKtorClient( - baseUrl, - client -) +class ContentRepoKtorClient private constructor( + readContentRepo: ReadContentRepo, + writeContentRepo: WriteContentRepo +) : ContentRepo, ReadContentRepo by readContentRepo, WriteContentRepo by writeContentRepo { + constructor( + baseUrl: String, + client: HttpClient = HttpClient { + install(WebSockets) + } + ) : this( + ReadContentRepoKtorClient( + "$baseUrl/$contentRootRoute", + client + ), + WriteContentRepoKtorClient( + "$baseUrl/$contentRootRoute", + client + ) + ) +} diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt index e9250fc4..568824bd 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt @@ -27,7 +27,7 @@ class ReadContentRepoKtorClient( standardKtorSerialFormat.load(RegisteredContent.serializer().nullable, it) } - override suspend fun getContentByPagination(pagination: Pagination): PaginationResult = client.get( + override suspend fun getContentByPagination(pagination: Pagination): PaginationResult = client.get( "$baseUrl/$getContentByPaginationRoute".includeQueryParams( pagination.asUrlQueryParts ) diff --git a/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/ContentRoutes.kt b/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/ContentRoutes.kt index f5ba141d..84c7452e 100644 --- a/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/ContentRoutes.kt +++ b/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/ContentRoutes.kt @@ -1,5 +1,7 @@ package com.insanusmokrassar.postssystem.core.ktor +const val contentRootRoute = "content" + const val getContentsIdsRoute = "getContentsIds" const val getContentByIdRoute = "getContentById" const val getContentByPaginationRoute = "getContentByPagination" diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ContentRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ContentRepoRoutingConfigurator.kt new file mode 100644 index 00000000..833cb6c0 --- /dev/null +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ContentRepoRoutingConfigurator.kt @@ -0,0 +1,26 @@ +package com.insanusmokrassar.postssystem.core.ktor.server.content + +import com.insanusmokrassar.postssystem.core.content.api.ContentRepo +import com.insanusmokrassar.postssystem.core.ktor.contentRootRoute +import com.insanusmokrassar.postssystem.ktor.server.configurators.ApplicationRoutingConfigurator +import io.ktor.routing.Route +import io.ktor.routing.route + +fun Route.configureContentRepoRoutes( + proxyTo: ContentRepo +) { + route( + contentRootRoute + ) { + configureReadContentRepoRoutes(proxyTo) + configureWriteContentRepoRoutes(proxyTo) + } +} + +class ContentRepoRoutingConfigurator( + private val proxyTo: ContentRepo +) : ApplicationRoutingConfigurator.Element { + override fun Route.invoke() { + configureContentRepoRoutes(proxyTo) + } +} \ No newline at end of file diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt new file mode 100644 index 00000000..c46205de --- /dev/null +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt @@ -0,0 +1,55 @@ +package com.insanusmokrassar.postssystem.core.ktor.server.content + +import com.insanusmokrassar.postssystem.core.content.RegisteredContent +import com.insanusmokrassar.postssystem.core.content.api.ReadContentRepo +import com.insanusmokrassar.postssystem.core.ktor.* +import com.insanusmokrassar.postssystem.ktor.server.configurators.ApplicationRoutingConfigurator +import com.insanusmokrassar.postssystem.ktor.server.extractPagination +import com.insanusmokrassar.postssystem.ktor.server.standardKtorSerialFormatContentType +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import io.ktor.application.call +import io.ktor.http.HttpStatusCode +import io.ktor.response.respond +import io.ktor.response.respondBytes +import io.ktor.routing.* +import kotlinx.serialization.builtins.nullable + +fun Route.configureReadContentRepoRoutes( + proxyTo: ReadContentRepo +) { + get(getContentsIdsRoute) { + call.respondBytes( + standardKtorSerialFormat.dump(contentIdsSerializer, proxyTo.getContentsIds()), + standardKtorSerialFormatContentType + ) + } + get("$getContentByIdRoute/{id}") { + val id = call.parameters["id"].also { + if (it == null) call.respond(HttpStatusCode.BadRequest, "Request must contains id in route") + } ?: return@get + call.respondBytes( + standardKtorSerialFormat.dump( + RegisteredContent.serializer().nullable, + proxyTo.getContentById(id) + ), + standardKtorSerialFormatContentType + ) + } + get(getContentByPaginationRoute) { + val pagination = call.request.queryParameters.extractPagination + call.respondBytes( + standardKtorSerialFormat.dump( + registeredContentPaginationResultSerializer, + proxyTo.getContentByPagination(pagination) + ) + ) + } +} + +class ReadContentRepoRoutingConfigurator( + private val proxyTo: ReadContentRepo +) : ApplicationRoutingConfigurator.Element { + override fun Route.invoke() { + configureReadContentRepoRoutes(proxyTo) + } +} diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt new file mode 100644 index 00000000..1fa2eb22 --- /dev/null +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt @@ -0,0 +1,63 @@ +package com.insanusmokrassar.postssystem.core.ktor.server.content + +import com.insanusmokrassar.postssystem.core.content.* +import com.insanusmokrassar.postssystem.core.content.api.WriteContentRepo +import com.insanusmokrassar.postssystem.core.ktor.* +import com.insanusmokrassar.postssystem.ktor.server.configurators.ApplicationRoutingConfigurator +import com.insanusmokrassar.postssystem.ktor.server.includeWebsocketHandling +import com.insanusmokrassar.postssystem.ktor.server.standardKtorSerialFormatContentType +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import io.ktor.application.call +import io.ktor.response.respondBytes +import io.ktor.routing.Route +import io.ktor.routing.post +import io.ktor.util.toByteArray +import kotlinx.serialization.builtins.nullable +import kotlinx.serialization.builtins.serializer + +fun Route.configureWriteContentRepoRoutes( + proxyTo: WriteContentRepo +) { + includeWebsocketHandling(contentCreatedFlowRoute, proxyTo.contentCreatedFlow) { + standardKtorSerialFormat.dump(RegisteredContent.serializer(), it) + } + includeWebsocketHandling(contentDeletedFlowRoute, proxyTo.contentDeletedFlow) { + standardKtorSerialFormat.dump(RegisteredContent.serializer(), it) + } + post(registerContentRoute) { + val content = standardKtorSerialFormat.load( + Content.serializer(), + call.request.receiveChannel().toByteArray() + ) + val registered = proxyTo.registerContent(content) + call.respondBytes( + standardKtorSerialFormat.dump( + RegisteredContent.serializer().nullable, + registered + ), + standardKtorSerialFormatContentType + ) + } + post(deleteContentRoute) { + val contentId = standardKtorSerialFormat.load( + ContentId.serializer(), + call.request.receiveChannel().toByteArray() + ) + val isDeleted = proxyTo.deleteContent(contentId) + call.respondBytes( + standardKtorSerialFormat.dump( + Boolean.serializer(), + isDeleted + ), + standardKtorSerialFormatContentType + ) + } +} + +class WriteContentRepoRoutingConfigurator( + private val proxyTo: WriteContentRepo +) : ApplicationRoutingConfigurator.Element { + override fun Route.invoke() { + configureWriteContentRepoRoutes(proxyTo) + } +} diff --git a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/PaginationInUrl.kt b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/PaginationInUrl.kt new file mode 100644 index 00000000..b30b5691 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/PaginationInUrl.kt @@ -0,0 +1,10 @@ +package com.insanusmokrassar.postssystem.ktor.server + +import com.insanusmokrassar.postssystem.utils.common.pagination.* +import io.ktor.http.Parameters + +val Parameters.extractPagination: Pagination + get() = SimplePagination( + get("page") ?.toIntOrNull() ?: 0, + get("size") ?.toIntOrNull() ?: defaultMediumPageSize + ) diff --git a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/configurators/ApplicationRoutingConfigurator.kt b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/configurators/ApplicationRoutingConfigurator.kt index 0e56e3b3..8ec15a65 100644 --- a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/configurators/ApplicationRoutingConfigurator.kt +++ b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/configurators/ApplicationRoutingConfigurator.kt @@ -1,6 +1,7 @@ package com.insanusmokrassar.postssystem.ktor.server.configurators import io.ktor.application.* +import io.ktor.routing.Route import io.ktor.routing.Routing import kotlinx.serialization.ContextualSerialization import kotlinx.serialization.Serializable @@ -9,7 +10,7 @@ import kotlinx.serialization.Serializable class ApplicationRoutingConfigurator( private val elements: List<@ContextualSerialization Element> ) : KtorApplicationConfigurator { - interface Element { operator fun Routing.invoke() } + interface Element { operator fun Route.invoke() } override fun Application.configure() { try { diff --git a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/standardKtorSerialFormatContentType.kt b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/standardKtorSerialFormatContentType.kt new file mode 100644 index 00000000..e7e0e422 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/standardKtorSerialFormatContentType.kt @@ -0,0 +1,5 @@ +package com.insanusmokrassar.postssystem.ktor.server + +import io.ktor.http.ContentType + +val standardKtorSerialFormatContentType = ContentType.Application.Cbor From 8c3a48db99148c29d2e2f68b9a700606913367f6 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 14 Aug 2020 13:17:27 +0600 Subject: [PATCH 2/3] complete client-server part for core api --- .../ktor/client/post/PostsRepoKtorClient.kt | 33 ++++--- .../client/post/WritePostsRepoKtorClient.kt | 4 +- .../postssystem/core/ktor/PostRoutes.kt | 2 + .../ReadContentRepoRoutingConfigurator.kt | 3 +- .../post/PostsRepoRoutingConfigurator.kt | 24 +++++ .../post/ReadPostsRepoRoutingConfigurator.kt | 93 +++++++++++++++++++ .../post/WritePostsRepoRoutingConfigurator.kt | 79 ++++++++++++++++ .../ktor/server/FromToDateTimeInUrl.kt | 11 +++ 8 files changed, 234 insertions(+), 15 deletions(-) create mode 100644 core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/PostsRepoRoutingConfigurator.kt create mode 100644 core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/ReadPostsRepoRoutingConfigurator.kt create mode 100644 core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FromToDateTimeInUrl.kt diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/PostsRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/PostsRepoKtorClient.kt index d60c795a..924607e9 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/PostsRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/PostsRepoKtorClient.kt @@ -1,18 +1,27 @@ package com.insanusmokrassar.postssystem.core.ktor.client.post +import com.insanusmokrassar.postssystem.core.ktor.postsRootRoute import com.insanusmokrassar.postssystem.core.post.repo.* import io.ktor.client.HttpClient import io.ktor.client.features.websocket.WebSockets -class PostsRepoKtorClient( - baseUrl: String, - client: HttpClient = HttpClient { - install(WebSockets) - } -) : PostsRepo, ReadPostsRepo by ReadPostsRepoKtorClient( - baseUrl, - client -), WritePostsRepo by WritePostsRepoKtorClient( - baseUrl, - client -) +class PostsRepoKtorClient private constructor( + readPostsRepo: ReadPostsRepo, + writePostsRepo: WritePostsRepo +) : PostsRepo, ReadPostsRepo by readPostsRepo, WritePostsRepo by writePostsRepo { + constructor( + baseUrl: String, + client: HttpClient = HttpClient { + install(WebSockets) + } + ) : this( + ReadPostsRepoKtorClient( + "${baseUrl}/$postsRootRoute", + client + ), + WritePostsRepoKtorClient( + "${baseUrl}/$postsRootRoute", + client + ) + ) +} diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt index 8e8f2dc6..b4d271ce 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt @@ -43,14 +43,14 @@ class WritePostsRepoKtorClient ( } override suspend fun deletePost(id: PostId): Boolean = client.post { - url("$baseUrl/$createPostRoute") + url("$baseUrl/$deletePostRoute") body = standardKtorSerialFormat.dump(PostId.serializer(), id) }.let { standardKtorSerialFormat.load(Boolean.serializer(), it) } override suspend fun updatePostContent(postId: PostId, post: Post): Boolean = client.post { - url("$baseUrl/$createPostRoute") + url("$baseUrl/$updatePostContentRoute") body = standardKtorSerialFormat.dump(UpdatePostObject.serializer(), UpdatePostObject(postId, post)) }.let { standardKtorSerialFormat.load(Boolean.serializer(), it) diff --git a/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/PostRoutes.kt b/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/PostRoutes.kt index 69633e2e..2e3f6c64 100644 --- a/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/PostRoutes.kt +++ b/core/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/PostRoutes.kt @@ -1,5 +1,7 @@ package com.insanusmokrassar.postssystem.core.ktor +const val postsRootRoute = "post" + const val getPostsIdsRoute = "getPostsIds" const val getPostByIdRoute = "getPostById" const val getPostsByContentRoute = "getPostsByContent" diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt index c46205de..01e5b467 100644 --- a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/ReadContentRepoRoutingConfigurator.kt @@ -1,5 +1,6 @@ package com.insanusmokrassar.postssystem.core.ktor.server.content +import com.insanusmokrassar.postssystem.core.content.ContentId import com.insanusmokrassar.postssystem.core.content.RegisteredContent import com.insanusmokrassar.postssystem.core.content.api.ReadContentRepo import com.insanusmokrassar.postssystem.core.ktor.* @@ -24,7 +25,7 @@ fun Route.configureReadContentRepoRoutes( ) } get("$getContentByIdRoute/{id}") { - val id = call.parameters["id"].also { + val id: ContentId = call.parameters["id"].also { if (it == null) call.respond(HttpStatusCode.BadRequest, "Request must contains id in route") } ?: return@get call.respondBytes( diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/PostsRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/PostsRepoRoutingConfigurator.kt new file mode 100644 index 00000000..beb217c8 --- /dev/null +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/PostsRepoRoutingConfigurator.kt @@ -0,0 +1,24 @@ +package com.insanusmokrassar.postssystem.core.ktor.server.post + +import com.insanusmokrassar.postssystem.core.ktor.postsRootRoute +import com.insanusmokrassar.postssystem.core.post.repo.PostsRepo +import com.insanusmokrassar.postssystem.ktor.server.configurators.ApplicationRoutingConfigurator +import io.ktor.routing.Route +import io.ktor.routing.route + +fun Route.configurePostsRepoRoutes( + proxyTo: PostsRepo +) { + route(postsRootRoute) { + configureReadPostsRepoRoutes(proxyTo) + configureWritePostsRepoRoutes(proxyTo) + } +} + +class PostsRepoRoutingConfigurator( + private val proxyTo: PostsRepo +) : ApplicationRoutingConfigurator.Element { + override fun Route.invoke() { + configurePostsRepoRoutes(proxyTo) + } +} diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/ReadPostsRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/ReadPostsRepoRoutingConfigurator.kt new file mode 100644 index 00000000..8a382995 --- /dev/null +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/ReadPostsRepoRoutingConfigurator.kt @@ -0,0 +1,93 @@ +package com.insanusmokrassar.postssystem.core.ktor.server.post + +import com.insanusmokrassar.postssystem.core.content.ContentId +import com.insanusmokrassar.postssystem.core.ktor.* +import com.insanusmokrassar.postssystem.core.post.PostId +import com.insanusmokrassar.postssystem.core.post.RegisteredPost +import com.insanusmokrassar.postssystem.core.post.repo.ReadPostsRepo +import com.insanusmokrassar.postssystem.ktor.server.* +import com.insanusmokrassar.postssystem.ktor.server.configurators.ApplicationRoutingConfigurator +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import com.insanusmokrassar.postssystem.utils.common.MAX_DATE +import com.insanusmokrassar.postssystem.utils.common.MIN_DATE +import io.ktor.application.call +import io.ktor.http.HttpStatusCode +import io.ktor.response.respond +import io.ktor.response.respondBytes +import io.ktor.routing.Route +import io.ktor.routing.get +import kotlinx.serialization.builtins.nullable + +fun Route.configureReadPostsRepoRoutes( + proxyTo: ReadPostsRepo +) { + get(getPostsIdsRoute) { + call.respondBytes( + standardKtorSerialFormat.dump(postIdsSerializer, proxyTo.getPostsIds()), + standardKtorSerialFormatContentType + ) + } + get("$getPostByIdRoute/{id}") { + val id: PostId = call.parameters["id"].also { + if (it == null) { + call.respond(HttpStatusCode.BadRequest, "request must contains id") + } + } ?: return@get + call.respondBytes( + standardKtorSerialFormat.dump( + RegisteredPost.serializer().nullable, + proxyTo.getPostById(id) + ), + standardKtorSerialFormatContentType + ) + } + get("$getPostsByContentRoute/{id}") { + val id: ContentId = call.parameters["id"].also { + if (it == null) { + call.respond(HttpStatusCode.BadRequest, "request must contains id") + } + } ?: return@get + call.respondBytes( + standardKtorSerialFormat.dump( + registeredPostsListSerializer, + proxyTo.getPostsByContent(id) + ), + standardKtorSerialFormatContentType + ) + } + get(getPostsByCreatingDatesRoute) { + val fromToDateTime = call.request.queryParameters.extractFromToDateTime + val pagination = call.request.queryParameters.extractPagination + + call.respondBytes( + standardKtorSerialFormat.dump( + registeredPostsPaginationResultSerializer, + proxyTo.getPostsByCreatingDates( + fromToDateTime.first ?: MIN_DATE, + fromToDateTime.second ?: MAX_DATE, + pagination + ) + ), + standardKtorSerialFormatContentType + ) + } + get(getPostsByPaginationRoute) { + val pagination = call.request.queryParameters.extractPagination + + call.respondBytes( + standardKtorSerialFormat.dump( + registeredPostsPaginationResultSerializer, + proxyTo.getPostsByPagination(pagination) + ), + standardKtorSerialFormatContentType + ) + } +} + +class ReadPostsRepoRoutingConfigurator( + private val proxyTo: ReadPostsRepo +) : ApplicationRoutingConfigurator.Element { + override fun Route.invoke() { + configureReadPostsRepoRoutes(proxyTo) + } +} diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt new file mode 100644 index 00000000..b4617082 --- /dev/null +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt @@ -0,0 +1,79 @@ +package com.insanusmokrassar.postssystem.core.ktor.server.post + +import com.insanusmokrassar.postssystem.core.ktor.* +import com.insanusmokrassar.postssystem.core.post.* +import com.insanusmokrassar.postssystem.core.post.repo.WritePostsRepo +import com.insanusmokrassar.postssystem.ktor.server.configurators.ApplicationRoutingConfigurator +import com.insanusmokrassar.postssystem.ktor.server.includeWebsocketHandling +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import io.ktor.application.call +import io.ktor.response.respondBytes +import io.ktor.routing.* +import io.ktor.util.toByteArray +import kotlinx.serialization.builtins.nullable +import kotlinx.serialization.builtins.serializer + +fun Route.configureWritePostsRepoRoutes( + proxyTo: WritePostsRepo +) { + includeWebsocketHandling(postCreatedFlowRoute, proxyTo.postCreatedFlow) { + standardKtorSerialFormat.dump(RegisteredPost.serializer(), it) + } + includeWebsocketHandling(postDeletedFlowRoute, proxyTo.postDeletedFlow) { + standardKtorSerialFormat.dump(RegisteredPost.serializer(), it) + } + includeWebsocketHandling(postUpdatedFlowRoute, proxyTo.postUpdatedFlow) { + standardKtorSerialFormat.dump(RegisteredPost.serializer(), it) + } + + post(createPostRoute) { + val post = standardKtorSerialFormat.load( + Post.serializer(), + call.request.receiveChannel().toByteArray() + ) + + call.respondBytes( + standardKtorSerialFormat.dump( + RegisteredPost.serializer().nullable, + proxyTo.createPost(post) + ) + ) + } + + post(deletePostRoute) { + val postId = standardKtorSerialFormat.load( + PostId.serializer(), + call.request.receiveChannel().toByteArray() + ) + + call.respondBytes( + standardKtorSerialFormat.dump( + Boolean.serializer(), + proxyTo.deletePost(postId) + ) + ) + } + + post(updatePostContentRoute) { + val updatePostObject = standardKtorSerialFormat.load( + UpdatePostObject.serializer(), + call.request.receiveChannel().toByteArray() + ) + + call.respondBytes( + standardKtorSerialFormat.dump( + Boolean.serializer(), + proxyTo.updatePostContent(updatePostObject.postId, updatePostObject.post) + ) + ) + } +} + +class WritePostsRepoRoutingConfigurator( + private val proxyTo: WritePostsRepo +) : ApplicationRoutingConfigurator.Element { + override fun Route.invoke() { + configureWritePostsRepoRoutes(proxyTo) + } + +} diff --git a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FromToDateTimeInUrl.kt b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FromToDateTimeInUrl.kt new file mode 100644 index 00000000..d35a4a96 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FromToDateTimeInUrl.kt @@ -0,0 +1,11 @@ +package com.insanusmokrassar.postssystem.ktor.server + +import com.insanusmokrassar.postssystem.ktor.FromToDateTime +import com.soywiz.klock.DateTime +import io.ktor.http.Parameters + +val Parameters.extractFromToDateTime: FromToDateTime + get() = FromToDateTime( + get("from") ?.toDoubleOrNull() ?.let { DateTime(it) }, + get("to") ?.toDoubleOrNull() ?.let { DateTime(it) } + ) From 6d6bed2eb075bb62ac74c3fd63b48e05173caead Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 14 Aug 2020 18:05:58 +0600 Subject: [PATCH 3/3] add unified way to make post and get requests from client --- .../content/ReadContentRepoKtorClient.kt | 21 +++++------ .../content/WriteContentRepoKtorClient.kt | 24 ++++++------ .../client/post/ReadPostsRepoKtorClient.kt | 37 +++++++++---------- .../client/post/WritePostsRepoKtorClient.kt | 36 ++++++++---------- .../ktor/client/StandardHttpClientGetPost.kt | 28 ++++++++++++++ 5 files changed, 81 insertions(+), 65 deletions(-) create mode 100644 ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/StandardHttpClientGetPost.kt diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt index 568824bd..4ec4c212 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/ReadContentRepoKtorClient.kt @@ -5,6 +5,7 @@ import com.insanusmokrassar.postssystem.core.content.RegisteredContent import com.insanusmokrassar.postssystem.core.content.api.ReadContentRepo import com.insanusmokrassar.postssystem.core.ktor.* import com.insanusmokrassar.postssystem.ktor.* +import com.insanusmokrassar.postssystem.ktor.client.uniget import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult import io.ktor.client.HttpClient @@ -21,17 +22,13 @@ class ReadContentRepoKtorClient( standardKtorSerialFormat.load(contentIdsSerializer, it) } - override suspend fun getContentById(id: ContentId): RegisteredContent? = client.get( - "$baseUrl/$getContentByIdRoute/$id" - ).let { - standardKtorSerialFormat.load(RegisteredContent.serializer().nullable, it) - } + override suspend fun getContentById(id: ContentId): RegisteredContent? = client.uniget( + "$baseUrl/$getContentByIdRoute/$id", + RegisteredContent.serializer().nullable + ) - override suspend fun getContentByPagination(pagination: Pagination): PaginationResult = client.get( - "$baseUrl/$getContentByPaginationRoute".includeQueryParams( - pagination.asUrlQueryParts - ) - ).let { - standardKtorSerialFormat.load(registeredContentPaginationResultSerializer, it) - } + override suspend fun getContentByPagination(pagination: Pagination): PaginationResult = client.uniget( + "$baseUrl/$getContentByPaginationRoute".includeQueryParams(pagination.asUrlQueryParts), + registeredContentPaginationResultSerializer + ) } \ No newline at end of file diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt index e7233e21..04126f49 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt @@ -3,7 +3,7 @@ package com.insanusmokrassar.postssystem.core.ktor.client.content import com.insanusmokrassar.postssystem.core.content.* import com.insanusmokrassar.postssystem.core.content.api.WriteContentRepo import com.insanusmokrassar.postssystem.core.ktor.* -import com.insanusmokrassar.postssystem.ktor.client.createStandardWebsocketFlow +import com.insanusmokrassar.postssystem.ktor.client.* import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import io.ktor.client.HttpClient import io.ktor.client.request.post @@ -28,17 +28,15 @@ class WriteContentRepoKtorClient( standardKtorSerialFormat.load(RegisteredContent.serializer(), it) } - override suspend fun registerContent(content: Content): RegisteredContent? = client.post { - url("$baseUrl/$registerContentRoute") - body = standardKtorSerialFormat.dump(Content.serializer(), content) - }.let { - standardKtorSerialFormat.load(RegisteredContent.serializer().nullable, it) - } + override suspend fun registerContent(content: Content): RegisteredContent? = client.unipost( + "$baseUrl/$registerContentRoute", + BodyPair(Content.serializer(), content), + RegisteredContent.serializer().nullable + ) - override suspend fun deleteContent(id: ContentId): Boolean = client.post { - url("$baseUrl/$deleteContentRoute") - body = standardKtorSerialFormat.dump(ContentId.serializer(), id) - }.let { - standardKtorSerialFormat.load(Boolean.serializer(), it) - } + override suspend fun deleteContent(id: ContentId): Boolean = client.unipost( + "$baseUrl/$deleteContentRoute", + BodyPair(ContentId.serializer(), id), + Boolean.serializer() + ) } \ No newline at end of file diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt index d5d9559f..768253f0 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt @@ -6,6 +6,7 @@ import com.insanusmokrassar.postssystem.core.post.PostId import com.insanusmokrassar.postssystem.core.post.RegisteredPost import com.insanusmokrassar.postssystem.core.post.repo.ReadPostsRepo import com.insanusmokrassar.postssystem.ktor.* +import com.insanusmokrassar.postssystem.ktor.client.uniget import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult import com.soywiz.klock.DateTime @@ -23,35 +24,31 @@ class ReadPostsRepoKtorClient( standardKtorSerialFormat.load(postIdsSerializer, it) } - override suspend fun getPostById(id: PostId): RegisteredPost? = client.get( - "$baseUrl/$getPostByIdRoute/$id" - ).let { - standardKtorSerialFormat.load(RegisteredPost.serializer().nullable, it) - } + override suspend fun getPostById(id: PostId): RegisteredPost? = client.uniget( + "$baseUrl/$getPostByIdRoute/$id", + RegisteredPost.serializer().nullable + ) - override suspend fun getPostsByContent(id: ContentId): List = client.get( - "$baseUrl/$getPostsByContentRoute/$id" - ).let { - standardKtorSerialFormat.load(registeredPostsListSerializer, it) - } + override suspend fun getPostsByContent(id: ContentId): List = client.uniget( + "$baseUrl/$getPostsByContentRoute/$id", + registeredPostsListSerializer + ) override suspend fun getPostsByCreatingDates( from: DateTime, to: DateTime, pagination: Pagination - ): PaginationResult = client.get( + ): PaginationResult = client.uniget( "$baseUrl/$getPostsByCreatingDatesRoute".includeQueryParams( (from to to).asFromToUrlPart + pagination.asUrlQueryParts - ) - ).let { - standardKtorSerialFormat.load(registeredPostsPaginationResultSerializer, it) - } + ), + registeredPostsPaginationResultSerializer + ) - override suspend fun getPostsByPagination(pagination: Pagination): PaginationResult = client.get( + override suspend fun getPostsByPagination(pagination: Pagination): PaginationResult = client.uniget( "$baseUrl/$getPostsByPaginationRoute".includeQueryParams( pagination.asUrlQueryParts - ) - ).let { - standardKtorSerialFormat.load(registeredPostsPaginationResultSerializer, it) - } + ), + registeredPostsPaginationResultSerializer + ) } \ No newline at end of file diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt index b4d271ce..ec4c283d 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt @@ -3,7 +3,7 @@ package com.insanusmokrassar.postssystem.core.ktor.client.post import com.insanusmokrassar.postssystem.core.ktor.* import com.insanusmokrassar.postssystem.core.post.* import com.insanusmokrassar.postssystem.core.post.repo.WritePostsRepo -import com.insanusmokrassar.postssystem.ktor.client.createStandardWebsocketFlow +import com.insanusmokrassar.postssystem.ktor.client.* import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import io.ktor.client.HttpClient import io.ktor.client.features.websocket.WebSockets @@ -35,25 +35,21 @@ class WritePostsRepoKtorClient ( standardKtorSerialFormat.load(RegisteredPost.serializer(), it) } - override suspend fun createPost(post: Post): RegisteredPost? = client.post { - url("$baseUrl/$createPostRoute") - body = standardKtorSerialFormat.dump(Post.serializer(), post) - }.let { - standardKtorSerialFormat.load(RegisteredPost.serializer().nullable, it) - } + override suspend fun createPost(post: Post): RegisteredPost? = client.unipost( + "$baseUrl/$createPostRoute", + BodyPair(Post.serializer(), post), + RegisteredPost.serializer().nullable + ) - override suspend fun deletePost(id: PostId): Boolean = client.post { - url("$baseUrl/$deletePostRoute") - body = standardKtorSerialFormat.dump(PostId.serializer(), id) - }.let { - standardKtorSerialFormat.load(Boolean.serializer(), it) - } - - override suspend fun updatePostContent(postId: PostId, post: Post): Boolean = client.post { - url("$baseUrl/$updatePostContentRoute") - body = standardKtorSerialFormat.dump(UpdatePostObject.serializer(), UpdatePostObject(postId, post)) - }.let { - standardKtorSerialFormat.load(Boolean.serializer(), it) - } + override suspend fun deletePost(id: PostId): Boolean = client.unipost( + "$baseUrl/$deletePostRoute", + BodyPair(PostId.serializer(), id), + Boolean.serializer() + ) + override suspend fun updatePostContent(postId: PostId, post: Post): Boolean = client.unipost( + "$baseUrl/$updatePostContentRoute", + BodyPair(UpdatePostObject.serializer(), UpdatePostObject(postId, post)), + Boolean.serializer() + ) } diff --git a/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/StandardHttpClientGetPost.kt b/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/StandardHttpClientGetPost.kt new file mode 100644 index 00000000..ed42c57c --- /dev/null +++ b/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/StandardHttpClientGetPost.kt @@ -0,0 +1,28 @@ +package com.insanusmokrassar.postssystem.ktor.client + +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.client.request.post +import kotlinx.serialization.* + +typealias BodyPair = Pair, T> + +suspend fun HttpClient.uniget( + url: String, + resultDeserializer: DeserializationStrategy +) = get( + url +).let { + standardKtorSerialFormat.load(resultDeserializer, it) +} + +suspend fun HttpClient.unipost( + url: String, + bodyInfo: BodyPair, + resultDeserializer: DeserializationStrategy +) = post(url) { + body = standardKtorSerialFormat.dump(bodyInfo.first, bodyInfo.second) +}.let { + standardKtorSerialFormat.load(resultDeserializer, it) +}