Skip to content

Commit

Permalink
(recipes): add ktor kotlin recipe with mongodb
Browse files Browse the repository at this point in the history
  • Loading branch information
osoykan committed May 14, 2024
1 parent 6b1e00a commit bee0200
Show file tree
Hide file tree
Showing 37 changed files with 879 additions and 47 deletions.
4 changes: 4 additions & 0 deletions recipes/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ subprojects {
java {
removeUnusedImports()
googleJavaFormat()
targetExclude("build")
targetExcludeIfContentContains("generated")
}
kotlin {
ktlint().setEditorConfigPath(rootProject.layout.projectDirectory.file(".editorconfig"))
targetExcludeIfContentContains("generated")
}
}

the<IdeaModel>().apply {
module {
isDownloadSources = true
Expand Down
51 changes: 44 additions & 7 deletions recipes/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ spring-kafka = "3.1.4"

# arrow
arrow = "1.2.4"
arrow-jackson = "0.14.1"
arrowSuspendApp = "0.4.0"

# Jackson
jackson = "2.17.1"
Expand All @@ -31,10 +33,14 @@ io-reactor-extensions = "1.2.2"

# Logging
slf4j = "2.0.13"
kotlinLogging = "6.0.9"

# Ktor
ktor = "2.3.11"
koin = "3.5.6"
koin-annotations = "1.3.1"

cohort = "2.5.0"

# R2DBC
r2dbc-spi = "1.0.0.RELEASE"
Expand All @@ -59,6 +65,7 @@ lombok = "1.18.32"

# Misc
hoplite = "2.8.0.RC3"
kediatr = "3.0.0"

# Testing
stove = "0.9.9-SNAPSHOT"
Expand All @@ -79,6 +86,12 @@ kotlinx-io-reactor-extensions = { module = "io.projectreactor.kotlin:reactor-kot

# Arrow
arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" }
arrow-jackson = { module = "io.arrow-kt:arrow-integrations-jackson-module", version.ref = "arrow-jackson" }
arrow-suspendApp = { module = "io.arrow-kt:suspendapp", version.ref = "arrowSuspendApp" }
arrow-suspendApp-ktor = { module = "io.arrow-kt:suspendapp-ktor", version.ref = "arrowSuspendApp" }
arrow-continuations = { module = "io.arrow-kt:arrow-continuations", version.ref = "arrow" }
arrow-fx-coroutines = { module = "io.arrow-kt:arrow-fx-coroutines", version.ref = "arrow" }
arrow-resilience = { module = "io.arrow-kt:arrow-resilience", version.ref = "arrow" }

# Spring
spring-boot = { module = "org.springframework.boot:spring-boot", version.ref = "spring-boot" }
Expand All @@ -105,23 +118,40 @@ jackson-core = { module = "com.fasterxml.jackson.core:jackson-core", version.ref

slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
ktor-server-call-logging = { module = "io.ktor:ktor-server-call-logging", version.ref = "ktor" }
ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-server-core-jvm = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor" }
ktor-server-config-yml = { module = "io.ktor:ktor-server-config-yaml", version.ref = "ktor" }
ktor-server-content-negotiation-jvm = { module = "io.ktor:ktor-server-content-negotiation-jvm", version.ref = "ktor" }
ktor-serialization-kotlinx-json-jvm = { module = "io.ktor:ktor-serialization-kotlinx-json-jvm", version.ref = "ktor" }
ktor-serialization-jackson-json = { module = "io.ktor:ktor-serialization-jackson", version.ref = "ktor" }
ktor-server-netty-jvm = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" }
ktor-server-statuspages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
ktor-server-callLogging = { module = "io.ktor:ktor-server-call-logging", version.ref = "ktor" }
ktor-server-autoHeadResponse = { module = "io.ktor:ktor-server-auto-head-response", version.ref = "ktor" }
ktor-server-cachingHeaders = { module = "io.ktor:ktor-server-caching-headers", version.ref = "ktor" }
ktor-server-callId = { module = "io.ktor:ktor-server-call-id-jvm", version.ref = "ktor" }
ktor-server-conditionalHeaders = { module = "io.ktor:ktor-server-conditional-headers", version.ref = "ktor" }
ktor-server-cors = { module = "io.ktor:ktor-server-cors-jvm", version.ref = "ktor" }
ktor-server-defaultHeaders = { module = "io.ktor:ktor-server-default-headers", version.ref = "ktor" }
ktor-swagger-ui = { module = "io.github.smiley4:ktor-swagger-ui", version = "2.9.0" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-plugins-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-jackson-json = { module = "io.ktor:ktor-serialization-jackson", version.ref = "ktor" }
koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-ktor = { module = "io.insert-koin:koin-ktor", version.ref = "koin" }
koin-logger-slf4j = { module = "io.insert-koin:koin-logger-slf4j", version.ref = "koin" }
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin-annotations" }
koin-ksp-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-annotations" }
kotlinFpUtil = { module = "it.czerwinski:kotlin-util", version = "1.9.1" }
cohort = { module = "com.sksamuel.cohort:cohort-ktor", version.ref = "cohort" }
cohort-logback = { module = "com.sksamuel.cohort:cohort-logback", version.ref = "cohort" }
r2dbc-spi = { module = "io.r2dbc:r2dbc-spi", version.ref = "r2dbc-spi" }
r2dbc-postgresql = { module = "io.r2dbc:r2dbc-postgresql", version.ref = "r2dbc-postgresql" }
elastic = { module = "co.elastic.clients:elasticsearch-java", version.ref = "elastic" }
mongodb-reactivestreams = { module = "org.mongodb:mongodb-driver-reactivestreams", version.ref = "mongodb" }
mongodb-bson-kotlin = { module = "org.mongodb:bson-kotlin", version.ref = "mongodb" }
mongodb-kotlin-coroutine = { module = "org.mongodb:mongodb-driver-kotlin-coroutine", version.ref = "mongodb" }
kotlin-logging-jvm = { module = "io.github.oshai:kotlin-logging-jvm", version.ref = "kotlinLogging" }

r2dbc-mssql = { module = "io.r2dbc:r2dbc-mssql", version.ref = "r2dbc-mssql" }
lettuce-core = { module = "io.lettuce:lettuce-core", version = "6.3.2.RELEASE" }
Expand All @@ -131,6 +161,11 @@ detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting",
hoplite = { module = "com.sksamuel.hoplite:hoplite-core", version.ref = "hoplite" }
hoplite-yaml = { module = "com.sksamuel.hoplite:hoplite-yaml", version.ref = "hoplite" }

# kediatR
kediatr-core = { module = "com.trendyol:kediatr-core", version.ref = "kediatr" }
kediatr-spring = { module = "com.trendyol:kediatr-spring-starter", version.ref = "kediatr" }
kediatr-koin = { module = "com.trendyol:kediatr-koin-starter", version.ref = "kediatr" }

# Tooling
lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" }

Expand All @@ -154,6 +189,7 @@ stove-testing-redis = { module = "com.trendyol:stove-testing-e2e-redis", version
stove-testing-wiremock = { module = "com.trendyol:stove-testing-e2e-wiremock", version.ref = "stove" }
stove-testing-elasticsearch = { module = "com.trendyol:stove-testing-e2e-elasticsearch", version.ref = "stove" }
stove-testing-rdbms-postgres = { module = "com.trendyol:stove-testing-e2e-rdbms-postgres", version.ref = "stove" }
stove-testing-mongodb = { module = "com.trendyol:stove-testing-e2e-mongodb", version.ref = "stove" }

# Scala
scala2-library = { module = "org.scala-lang:scala-library", version.ref = "scala2x" }
Expand All @@ -166,5 +202,6 @@ kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
testLogger = { id = "com.adarshr.test-logger", version = "4.0.0" }
ksp = { id = "com.google.devtools.ksp", version = "1.9.23-1.0.20" }


Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.trendyol.stove.examples.java.spring;

import com.trendyol.stove.examples.java.spring.infra.boilerplate.couchbase.CouchbaseConfiguration;
import com.trendyol.stove.examples.java.spring.infra.boilerplate.kafka.KafkaConfiguration;
import java.util.function.Consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand All @@ -10,7 +9,7 @@
import org.springframework.kafka.annotation.EnableKafka;

@SpringBootApplication
@EnableConfigurationProperties({CouchbaseConfiguration.class, KafkaConfiguration.class})
@EnableConfigurationProperties({CouchbaseConfiguration.class})
@EnableKafka
public class ExampleSpringBootApp {
public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

import com.trendyol.stove.examples.domain.product.Product;
import com.trendyol.stove.examples.java.spring.application.external.category.CategoryHttpApi;
import com.trendyol.stove.examples.java.spring.domain.ProductRepository;
import com.trendyol.stove.examples.java.spring.domain.ProductReactiveRepository;
import com.trendyol.stove.recipes.shared.application.BusinessException;
import com.trendyol.stove.recipes.shared.application.category.CategoryApiResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class ProductApplicationService {
private final ProductRepository productRepository;
private final ProductReactiveRepository productRepository;
private final CategoryHttpApi categoryHttpApi;

public ProductApplicationService(
ProductRepository productRepository, CategoryHttpApi categoryHttpApi) {
ProductReactiveRepository productRepository, CategoryHttpApi categoryHttpApi) {
this.productRepository = productRepository;
this.categoryHttpApi = categoryHttpApi;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
import com.trendyol.stove.examples.domain.product.Product;
import reactor.core.publisher.Mono;

public interface ProductRepository {
public interface ProductReactiveRepository {
Mono<Void> save(Product product);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.slf4j.Logger;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
Expand All @@ -20,6 +21,17 @@
public class KafkaBeanConfiguration {
private final Logger logger = org.slf4j.LoggerFactory.getLogger(KafkaBeanConfiguration.class);

@Bean
@ConfigurationProperties(prefix = "kafka")
public KafkaConfiguration kafkaConfiguration() {
return new KafkaConfiguration();
}

@Bean
public TopicResolver topicResolver(KafkaConfiguration kafkaConfiguration) {
return new TopicResolver(kafkaConfiguration);
}

@Bean
public Properties consumerProperties(KafkaConfiguration kafkaConfiguration) {
Properties properties = new Properties();
Expand All @@ -36,8 +48,9 @@ public Properties consumerProperties(KafkaConfiguration kafkaConfiguration) {
ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,
(int) Duration.ofSeconds(kafkaConfiguration.getSessionTimeoutSeconds()).toMillis());
properties.put(
ConsumerConfig.ALLOW_AUTO_CREATE_TOPICS_CONFIG, kafkaConfiguration.autoCreateTopics);
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, kafkaConfiguration.autoOffsetReset);
ConsumerConfig.ALLOW_AUTO_CREATE_TOPICS_CONFIG, kafkaConfiguration.isAutoCreateTopics());
properties.put(
ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, kafkaConfiguration.getAutoOffsetReset());
properties.put(
ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
properties.put(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import java.util.Map;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "kafka")
public @Data class KafkaConfiguration {
String bootstrapServers;
String groupId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.trendyol.stove.examples.domain.ddd.AggregateRoot;
import com.trendyol.stove.examples.java.spring.domain.EventPublisher;
import com.trendyol.stove.examples.domain.ddd.EventPublisher;
import java.util.stream.Stream;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.slf4j.Logger;
Expand Down Expand Up @@ -39,9 +39,9 @@ private <TId> Stream<ProducerRecord<String, Object>> mapEventsToProducerRecords(
event -> {
var topic = topicResolver.resolve(aggregateRoot.getAggregateName());
try {
logger.info("Publishing event {} to topic {}", event, topic.name);
logger.info("Publishing event {} to topic {}", event, topic.getName());
return new ProducerRecord<>(
topic.name,
topic.getName(),
aggregateRoot.getIdAsString(),
objectMapper.writeValueAsString(event));
} catch (JsonProcessingException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.trendyol.stove.examples.java.spring.infra.boilerplate.kafka;

import org.springframework.stereotype.Component;

@Component
public class TopicResolver {
private final KafkaConfiguration kafkaConfiguration;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

import com.couchbase.client.java.ReactiveBucket;
import com.couchbase.client.java.ReactiveCollection;
import com.trendyol.stove.examples.domain.ddd.EventPublisher;
import com.trendyol.stove.examples.domain.product.Product;
import com.trendyol.stove.examples.java.spring.domain.EventPublisher;
import com.trendyol.stove.examples.java.spring.domain.ProductRepository;
import com.trendyol.stove.examples.java.spring.domain.ProductReactiveRepository;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class ProductRepositoryImpl implements ProductRepository {
public class CouchbaseProductRepository implements ProductReactiveRepository {
private final ReactiveBucket bucket;
private final EventPublisher eventPublisher;

public ProductRepositoryImpl(ReactiveBucket bucket, EventPublisher eventPublisher) {
public CouchbaseProductRepository(ReactiveBucket bucket, EventPublisher eventPublisher) {
this.bucket = bucket;
this.eventPublisher = eventPublisher;
}
Expand Down
40 changes: 37 additions & 3 deletions recipes/kotlin-recipes/ktor-recipe/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
dependencies {

implementation(projects.shared.domain)
implementation(projects.shared.application)
implementation(libs.ktor.server.core.jvm)
implementation(libs.ktor.server.netty.jvm)
implementation(libs.ktor.server.content.negotiation.jvm)
implementation(libs.ktor.server.statuspages)
implementation(libs.ktor.server.callLogging)
implementation(libs.ktor.server.callId)
implementation(libs.ktor.server.conditionalHeaders)
implementation(libs.ktor.server.cors)
implementation(libs.ktor.server.defaultHeaders)
implementation(libs.ktor.server.cachingHeaders)
implementation(libs.ktor.server.autoHeadResponse)
implementation(libs.ktor.server.config.yml)
implementation(libs.ktor.swagger.ui)
implementation(libs.ktor.serialization.jackson.json)
implementation(libs.koin)
implementation(libs.koin.ktor)
implementation(libs.slf4j.api)
implementation(libs.arrow.core)
implementation(libs.hoplite)
implementation(libs.hoplite.yaml)
implementation(libs.logback.classic)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.plugins.logging)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.kotlinFpUtil)
implementation(libs.kotlin.logging.jvm)
implementation(libs.kediatr.koin)
implementation(libs.mongodb.kotlin.coroutine)
implementation(libs.mongodb.bson.kotlin)
}

dependencies {
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotest.framework.api.jvm)
testImplementation(libs.kotest.property.jvm)
testImplementation(libs.stove.testing)
testImplementation(libs.stove.testing.couchbase)
testImplementation(libs.stove.testing.mongodb)
testImplementation(libs.stove.testing.http)
testImplementation(libs.stove.testing.wiremock)
testImplementation(libs.stove.testing.kafka)
testImplementation(libs.stove.spring.testing)
testImplementation(libs.stove.ktor.testing)
testImplementation(libs.jackson.kotlin)
}


Loading

0 comments on commit bee0200

Please sign in to comment.