From f2be9fb3cdca2ad95ddf5cf8e76f6c4b92b02de2 Mon Sep 17 00:00:00 2001 From: ccornu <ccornu@takima.fr> Date: Fri, 7 Feb 2025 14:38:31 +0100 Subject: [PATCH] feat: configure DB integration + koin + Readme update --- README.md | 63 +++++++++++------------- build.gradle.kts | 4 +- docker/db/README.md | 17 +++++++ gradle.properties | 3 +- src/main/kotlin/Application.kt | 7 +-- src/main/kotlin/DynamoDbConfiguration.kt | 58 ++++++++++++++++++++++ src/main/kotlin/Frameworks.kt | 25 ---------- src/main/kotlin/Koin.kt | 22 +++++++++ src/main/kotlin/Routing.kt | 13 ----- src/main/resources/application.yaml | 2 + 10 files changed, 138 insertions(+), 76 deletions(-) create mode 100644 docker/db/README.md create mode 100644 src/main/kotlin/DynamoDbConfiguration.kt delete mode 100644 src/main/kotlin/Frameworks.kt create mode 100644 src/main/kotlin/Koin.kt delete mode 100644 src/main/kotlin/Routing.kt diff --git a/README.md b/README.md index 4bcf77f..c185f27 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,42 @@ -# tournament-api +# Tournament API -This project was created using the [Ktor Project Generator](https://start.ktor.io). +## Initalisation -Here are some useful links to get you started: +### Pre-requisites -- [Ktor Documentation](https://ktor.io/docs/home.html) -- [Ktor GitHub page](https://github.com/ktorio/ktor) -- The [Ktor Slack chat](https://app.slack.com/client/T09229ZC6/C0A974TJ9). You'll need - to [request an invite](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) to join. +You need to have Docker and AWS CLI installed on your machine -## Features +### How to start the database -Here's a list of features included in this project: +In `docker/db` folder, run the following command: -| Name | Description | -| --------------------------------------------------------------------|------------------------------------------------------------------------------------ | -| [Routing](https://start.ktor.io/p/routing) | Provides a structured routing DSL | -| [Authentication](https://start.ktor.io/p/auth) | Provides extension point for handling the Authorization header | -| [OpenAPI](https://start.ktor.io/p/openapi) | Serves OpenAPI documentation | -| [Koin](https://start.ktor.io/p/koin) | Provides dependency injection | -| [Content Negotiation](https://start.ktor.io/p/content-negotiation) | Provides automatic content conversion according to Content-Type and Accept headers | -| [Jackson](https://start.ktor.io/p/ktor-jackson) | Handles JSON serialization using Jackson library | +```bash +docker compose up -d +``` -## Building & Running +### How to start the API -To build or run the project, use one of the following tasks: +Place yourself at root and start -| Task | Description | -| -------------------------------|---------------------------------------------------------------------- | -| `./gradlew test` | Run the tests | -| `./gradlew build` | Build everything | -| `buildFatJar` | Build an executable JAR of the server with all dependencies included | -| `buildImage` | Build the docker image to use with the fat JAR | -| `publishImageToLocalRegistry` | Publish the docker image locally | -| `run` | Run the server | -| `runDocker` | Run using the local docker image | +```bash +docker compose up -d +``` -If the server starts successfully, you'll see the following output: +## Available endpoints -``` -2024-12-04 14:32:45.584 [main] INFO Application - Application started in 0.303 seconds. -2024-12-04 14:32:45.682 [main] INFO Application - Responding at http://0.0.0.0:8080 -``` +## I want to ensure tests are running + +## Left to do +- [x] setup dynamo DB +- [x] faire la connexion avec Dynamo +- 1er endpoint + - [x] créer l'entité joueur + - [ ] créer le repo et le connecter à la BD + - [ ] tester unitairement le service + - [ ] tester l'intégration complète +- [ ] endpoint fonctionnel pour l'ajout d'un avec test + - [ ] tests d'inté + - [ ] tests unitaires +- [ ] tous les endpoints autres +- [ ] gestion de la sécurité \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 97793e0..ad35518 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,11 +3,12 @@ val kotlin_version: String by project val logback_version: String by project val dynamo_version: String by project val dynamo_kt_version: String by project +val mockk_version: String by project plugins { kotlin("jvm") version "2.1.10" - id("io.ktor.plugin") version "3.0.3" + id("io.ktor.plugin") version "2.3.13" } group = "betclic.test" @@ -39,5 +40,6 @@ dependencies { implementation("software.amazon.awssdk:dynamodb:$dynamo_version") implementation("dev.andrewohara:dynamokt:$dynamo_kt_version") testImplementation("io.ktor:ktor-server-test-host") + testImplementation("io.mockk:mockk:$mockk_version") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") } diff --git a/docker/db/README.md b/docker/db/README.md new file mode 100644 index 0000000..f3d2948 --- /dev/null +++ b/docker/db/README.md @@ -0,0 +1,17 @@ +# Local Database + +Use this docker-compose file to run a local database for development. + +## Usage + +### Pre-requisites + +You need to have Docker and AWS CLI installed on your machine + +### How to start the database + +In `docker/db` folder, run the following command: + +```bash +docker compose up +``` diff --git a/gradle.properties b/gradle.properties index d7945c5..4bf19e4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,6 @@ koin_version=3.5.6 kotlin_version=2.1.10 dynamo_version=2.28.1 dynamo_kt_version=1.0.0 -ktor_version=3.0.3 +ktor_version=2.3.13 logback_version=1.4.14 +mockk_version=1.10.0 diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt index 08311e3..074276f 100644 --- a/src/main/kotlin/Application.kt +++ b/src/main/kotlin/Application.kt @@ -1,15 +1,16 @@ package betclic.test +import betclic.test.player.configureRouting import io.ktor.server.application.* +import kotlinx.coroutines.runBlocking fun main(args: Array<String>) { io.ktor.server.netty.EngineMain.main(args) } -fun Application.module() { - configureSecurity() +fun Application.module() = runBlocking { configureHTTP() - configureFrameworks() + configureKoin() configureSerialization() configureRouting() } diff --git a/src/main/kotlin/DynamoDbConfiguration.kt b/src/main/kotlin/DynamoDbConfiguration.kt new file mode 100644 index 0000000..8c3d3ad --- /dev/null +++ b/src/main/kotlin/DynamoDbConfiguration.kt @@ -0,0 +1,58 @@ +package betclic.test + +import betclic.test.player.PlayerEntity +import dev.andrewohara.dynamokt.DataClassTableSchema +import io.ktor.server.application.* +import kotlinx.coroutines.future.await +import org.slf4j.LoggerFactory +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient +import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient +import java.net.URI +import kotlin.reflect.KClass + +class DynamoDbConfiguration() { + private val logger = LoggerFactory.getLogger(DynamoDbConfiguration::class.java) + fun dataSource(): DynamoDbEnhancedAsyncClient { + logger.info("Using dynamo-db config") + return DynamoDbEnhancedAsyncClient.builder() + .dynamoDbClient(createDynamoDbClient()) + .build() + } +} + +private fun createDynamoDbClient(): DynamoDbAsyncClient { + return DynamoDbAsyncClient.builder().endpointOverride(URI("http://localhost:8000")).build() +} + +fun Application.createEnhancedDynamoDbClient(dynamoDbClient: DynamoDbAsyncClient): DynamoDbEnhancedAsyncClient { + return DynamoDbEnhancedAsyncClient.builder() + .dynamoDbClient(dynamoDbClient) + .build() +} + +suspend fun createNecessaryTables( + dynamoDbClient: DynamoDbAsyncClient, + dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient +) { + val existingTables = dynamoDbClient.listTables().await().tableNames().toList() + + listOf(PlayerEntity::class).forEach { + createTableIfNotExists(existingTables, it, dynamoDbEnhancedClient) + } +} + +private val logger = LoggerFactory.getLogger(Application::class.java) + +private suspend fun <T : Any> createTableIfNotExists( + existingTables: List<String>, + item: KClass<T>, + dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient +) { + val tableSchema = DataClassTableSchema(item) + if (existingTables.contains(item.simpleName)) { + logger.info("Table '${item.simpleName}' already exists.") + } else { + dynamoDbEnhancedClient.table(item.simpleName, tableSchema).createTable().await() + logger.info("Table '${item.simpleName}' created successfully.") + } +} \ No newline at end of file diff --git a/src/main/kotlin/Frameworks.kt b/src/main/kotlin/Frameworks.kt deleted file mode 100644 index 7e7b4de..0000000 --- a/src/main/kotlin/Frameworks.kt +++ /dev/null @@ -1,25 +0,0 @@ -package betclic.test - -import com.fasterxml.jackson.databind.* -import io.ktor.serialization.jackson.* -import io.ktor.server.application.* -import io.ktor.server.plugins.contentnegotiation.* -import io.ktor.server.plugins.openapi.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import org.koin.dsl.module -import org.koin.ktor.plugin.Koin -import org.koin.logger.slf4jLogger - -fun Application.configureFrameworks() { - install(Koin) { - slf4jLogger() - modules(module { - single<HelloService> { - HelloService { - println(environment.log.info("Hello, World!")) - } - } - }) - } -} diff --git a/src/main/kotlin/Koin.kt b/src/main/kotlin/Koin.kt new file mode 100644 index 0000000..e8afee5 --- /dev/null +++ b/src/main/kotlin/Koin.kt @@ -0,0 +1,22 @@ +package betclic.test + +import betclic.test.player.PlayerRepository +import betclic.test.player.PlayerService +import betclic.test.player.PlayerServiceImpl +import io.ktor.server.application.* +import org.koin.dsl.module +import org.koin.ktor.plugin.Koin +import org.koin.logger.slf4jLogger + +fun Application.configureKoin() { + install(Koin) { + slf4jLogger() + modules(playerModule) + } +} + +val playerModule = module { + single { DynamoDbConfiguration().dataSource() } + single<PlayerRepository> { PlayerRepository(get()) } + single<PlayerService> { PlayerServiceImpl(get()) } +} diff --git a/src/main/kotlin/Routing.kt b/src/main/kotlin/Routing.kt deleted file mode 100644 index d89e2e8..0000000 --- a/src/main/kotlin/Routing.kt +++ /dev/null @@ -1,13 +0,0 @@ -package betclic.test - -import io.ktor.server.application.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -fun Application.configureRouting() { - routing { - get("/") { - call.respondText("Hello World!") - } - } -} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 23f6a01..bd3c34f 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -4,3 +4,5 @@ ktor: - betclic.test.ApplicationKt.module deployment: port: 8080 + database: + dynamodbUrl: "http://localhost:8000" -- GitLab