<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Coroutines Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/coroutines/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:49:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>Coroutines Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>MongoDB with Kotlin Coroutines in Ktor</title>
		<link>https://blog.codersee.com/mongodb-kotlin-coroutines-ktor/</link>
					<comments>https://blog.codersee.com/mongodb-kotlin-coroutines-ktor/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Wed, 26 Feb 2025 16:00:00 +0000</pubDate>
				<category><![CDATA[Ktor]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Mongo]]></category>
		<category><![CDATA[MongoDB]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=17012558</guid>

					<description><![CDATA[<p>In this lesson, we are going to learn how to work with MongoDB and coroutines using the MongoDB Kotlin Driver in Ktor.</p>
<p>The post <a href="https://blog.codersee.com/mongodb-kotlin-coroutines-ktor/">MongoDB with Kotlin Coroutines in Ktor</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this article, I will show you how to work with MongoDB and Kotlin coroutines in a Ktor application. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Note: this article was created based on one of the services we implement in my <a href="https://codersee.com/courses/ktor-server-pro/">Ktor Server Pro course</a>. If you would like to learn how to expose a fully functional REST API, secure the application, and many many more, then don&#8217;t hesitate and secure your spot today😉</p>
</blockquote>



<p>Before we start, I just wanted to mention that at the moment of writing <strong>KMongo is officially deprecated! </strong>Maybe you saw my previous article, maybe you saw some outdated content in some other places. Either way, we should not use that library anymore in favor of the official driver that comes in two flavors:</p>



<ul class="wp-block-list">
<li><strong>MongoDB Kotlin Driver (for applications using coroutines)</strong></li>



<li>MongoDB Kotlin Sync Driver (for apps that require synchronous processing)</li>
</ul>



<h2 class="wp-block-heading" id="h-video-content">Video Content</h2>



<p>As always, if you prefer a video content, then please check out my latest YouTube video:</p>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><a href="https://blog.codersee.com/mongodb-kotlin-coroutines-ktor/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2F8NfdOv2R-4U%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /><figcaption></figcaption></figure>


<h2 class="wp-block-heading" id="h-create-amp-verify-mongodb-instance">Create &amp; Verify MongoDB Instance</h2>



<p>If you already have a MongoDB instance installed on your machine, feel free to skip this step.</p>



<p>On the other hand, if that is not the case, you can install it using the <a href="https://www.mongodb.com/docs/manual/installation/">official manual</a>. Or, if you just like me have a Docker environment, you can run the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">docker run --name my_awesome_mongo_name -d -p 27017:27017 mongo:8.0.4</pre>



<p>This way, we run the Mongo docker container and expose it&#8217;s port <code>27017</code> .</p>



<p>And to verify it running, we can run the <code>docker ps</code> :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                      NAMES
9ecd8986ac34   mongo:8.0.4   "docker-entrypoint.s…"   20 seconds ago   Up 19 seconds   0.0.0.0:27017->27017/tcp   my_awesome_mongo_name</pre>



<p>As we can see, it was created successfully and we should be able to connect to it at <code>localhost:27017</code></p>



<p>We can assert that, as well, for example with a free and official tool- <a href="https://www.mongodb.com/try/download/compass">MongoDB Compass</a>:</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="599" src="http://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_verify_connection_compass-1024x599.png" alt="Image is a screenshot from MongoDB Compass application and shows how to establish a new connection to mongo instance." class="wp-image-17012563" srcset="https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_verify_connection_compass-1024x599.png 1024w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_verify_connection_compass-300x176.png 300w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_verify_connection_compass-768x450.png 768w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_verify_connection_compass.png 1411w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>And if we are able to connect, it means that we can head to the next step. </p>



<h2 class="wp-block-heading" id="h-create-a-new-ktor-project">Create a New Ktor Project</h2>



<p>Nextly, let&#8217;s navigate to the <a href="https://start.ktor.io/" target="_blank" rel="noreferrer noopener">Ktor Project Generator</a> page to create a fresh project from scratch. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>If you use the IntelliJ Ultimate Edition, then you can generate it in your IDE</p>
</blockquote>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="468" src="http://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_create_project_in_generator-1024x468.png" alt="Image is a screenshot from Ktor Generator Page and shows necessary settings for our project." class="wp-image-17012564" srcset="https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_create_project_in_generator-1024x468.png 1024w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_create_project_in_generator-300x137.png 300w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_create_project_in_generator-768x351.png 768w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_create_project_in_generator.png 1230w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>As we can see, we will be using <strong>Ktor 3.1.0</strong> with <strong>Netty</strong> and configuration in the <strong>YAML</strong> file.</p>



<p>The <strong>important </strong>thing to mention here is that if we want to work with Kotlin coroutines, <strong>we should not select the below MongoDB plugin:</strong></p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="373" src="http://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo-1024x373.png" alt="Image shows MongoDB plugin for Ktor that we should not use when working with coroutines. " class="wp-image-17012565" srcset="https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo-1024x373.png 1024w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo-300x109.png 300w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo-768x279.png 768w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo.png 1223w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Because as we can see, this adds the MongoDB Kotlin Sync Driver for synchronous processing:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="828" src="http://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo_preview-1024x828.png" alt="" class="wp-image-17012566" srcset="https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo_preview-1024x828.png 1024w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo_preview-300x243.png 300w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo_preview-768x621.png 768w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_coroutines_project_generator_sync_mongo_preview.png 1224w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>So, in our case, to keep our Ktor application as vanilla as possible, we will not add any additional plugins. </p>



<p>With that done, let&#8217;s hit the <em>Download</em> button and let&#8217;s import the project to our IDE.</p>



<h2 class="wp-block-heading" id="h-add-mongodb-async-driver-to-ktor">Add MongoDB Async Driver to Ktor</h2>



<p>Before adding the necessary import, let&#8217;s perform a small cleanup. </p>



<p>Firstly, let&#8217;s remove the <code>Routing.kt</code> file- we don&#8217;t need it for this tutorial.</p>



<p>Then, let&#8217;s navigate to the <code>Application.kt</code> and let&#8217;s get rid of routing config, as well. Eventually, we should have something like that: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> package com.codersee

import io.ktor.server.application.*

fun main(args: Array&lt;String>) {
    io.ktor.server.netty.EngineMain.main(args)
}

fun Application.module() {}</pre>



<p>With that done, let&#8217;s add the MongoDB Kotlin Driver to work with coroutines. </p>



<p>During the configuration, we decided to use the Gradle version catalog. So now, we must navigate to the <code>libs.versions.toml</code> inside the <code>gradle</code> directory and add the <code>mongodb-version</code> along with <code>mongodb-driver-kotlin</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[versions]
kotlin-version = "2.1.10"
ktor-version = "3.1.0"
logback-version = "1.4.14"
mongodb-version = "5.3.1"

[libraries]
ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor-version" }
ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor-version" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback-version" }
ktor-server-config-yaml = { module = "io.ktor:ktor-server-config-yaml", version.ref = "ktor-version" }
ktor-server-test-host = { module = "io.ktor:ktor-server-test-host", version.ref = "ktor-version" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin-version" }
mongodb-driver-kotlin = { module = "org.mongodb:mongodb-driver-kotlin-coroutine", version.ref = "mongodb-version" }

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" }
ktor = { id = "io.ktor.plugin", version.ref = "ktor-version" }</pre>



<p>With that done, let&#8217;s navigate to <code>build.gradle.kts</code> and add the following line: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">implementation(libs.mongodb.driver.kotlin)</pre>



<p>Lastly, let&#8217;s sync the gradle project so that the necessary libraries are fetched. </p>



<h2 class="wp-block-heading" id="h-introduce-model-classes">Introduce Model Classes</h2>



<p>Before we can start working with coroutines, we must prepare classes that will be translated into Mongo documents and vice versa. </p>



<p>To do so, let&#8217;s create the <code>Product.kt</code> class and put the following:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.bson.codecs.pojo.annotations.BsonId
import org.bson.types.ObjectId

data class Product(
    @BsonId
    val id: ObjectId? = null,
    val name: String,
    val description: String,
    val price: Double,
    val category: ProductCategory,
    val tags: List&lt;ProductTag>,
)

enum class ProductCategory {
    VIDEO_GAMES, TOOLS, HOME_AND_KITCHEN, FOOD
}

enum class ProductTag {
    EXCLUSIVE, HANDMADE, ORGANIC, BESTSELLER
}</pre>



<p>As we can see, all fields except the <em>id</em> field are plain Kotlin classes. And later, they will be serialized/deserialized 1:1 when saving and retrieving from the database. </p>



<p>When it comes to the <code>id</code> field, we mark it using the <code>@BsonId</code> annotation. Thanks to that, it will be serialized to the <code>_id</code> BSON field that represents a primary key of our document. Moreover, we assign a default null value to it. This way, the value will be generated automatically. </p>



<h2 class="wp-block-heading" id="h-configure-ktor-connection-to-mongodb">Configure Ktor Connection to MongoDB</h2>



<p>As the next step, let&#8217;s connect our Ktor application to the Mongo instance. </p>



<p>And for that purpose, let&#8217;s navigate to <code>Application.kt</code> and implement the following logic: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun Application.module() {
    val settings = MongoClientSettings.builder()
        .applyConnectionString(
            ConnectionString("mongodb://localhost:27017")
        )
        .build()

    val client = MongoClient.create(settings)
    val database = client.getDatabase("application")
    val productCollection = database.getCollection&lt;Product>("products")
}</pre>



<p>Firstly, we instantiate the <em>MongoClientSettings</em> builder. A builder that allows us to configure the connection string for our database. Additionally, if you are looking for more configuration options, like reads or writes repetition, then you should start in there. </p>



<p>Then, we create a new client and pass our settings to it. If you would like to, then you could use another variant of the <code>create</code> function that takes the connection String as an argument:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public fun create(connectionString: String): MongoClient</pre>



<p>But, in my opinion, using the builder approach is a better choice in terms of extensibility. </p>



<p>With that done, we get the instance of our database, by passing its name. Lastly, we obtain the MongoCollection that we will be injecting later into the product repository. Again, we pass the name of our collection, too.</p>



<p>To verify, let&#8217;s run our application.</p>



<p>As a result, we should see the following text in the logs indicating that everything is perfectly fine: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[cluster-ClusterId{value='67bd5f4689251d25d5077fb7', description='null'}-localhost:27017] INFO  org.mongodb.driver.cluster - Monitor thread successfully connected to server with description ServerDescription{address=localhost:27017, type=STANDALONE, cryptd=false, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=25, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=26289200, minRoundTripTimeNanos=0}</pre>



<h2 class="wp-block-heading" id="h-mongodb-coroutines-crud-operations">MongoDB Coroutines CRUD Operations</h2>



<p>After we did all of that preparation, we can finally create the <code>ProductRepository</code> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class ProductRepository(
    private val productCollection: MongoCollection&lt;Product>,
) { }</pre>



<p>And inject the collection in <code>Application.kt</code> : </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val productRepository = ProductRepository(productCollection)</pre>



<p>The constructor injection is a great way to make our code easier to test in the future. </p>



<p>Anyway, coming back to the topic, let&#8217;s learn how we can how we can perform basic CRUD operations with coroutines. </p>



<h3 class="wp-block-heading" id="h-persits-products">Persits Products</h3>



<p>Initially, our <code>products</code> collection is empty, so let&#8217;s add the following code to start populating it: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun save(product: Product): Product? {
    val result = productCollection.insertOne(product)

    return result.insertedId
        ?.let { product.copy(id = it.asObjectId().value) }
}</pre>



<p>First of all, we must make our function <em>suspend</em>. Why? Because the <em>insertOne</em> we use is a suspend function, so we must invoke it either from the coroutine or another suspend function. </p>



<p>When it comes to the persisting- the function that we use returns the <code>InsertOneResult</code> that allows us to either get a boolean informing if the write was acknowledged or the generated identifier of the saved product. And in my opinion, reading that and returning a Product instance with the updated field is a quite nice approach. </p>



<p>After that, let&#8217;s get back to the <code>Application.kt</code> and test this function: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val saved = runBlocking {
    productRepository.save(
        Product(
            name = "Product 1",
            description = "Description 1",
            price = 19.99,
            category = ProductCategory.TOOLS,
            tags = listOf(ProductTag.EXCLUSIVE, ProductTag.BESTSELLER)
        )
    )
}

println(saved)</pre>



<p>I know, the good, old println 🤠 </p>



<p>Anyway, if we run our application, we should see the following in the logs: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Product(id=67bd62f974edd96bbd59874a, name=Product 1, description=Description 1, price=19.99, category=TOOLS, tags=[EXCLUSIVE, BESTSELLER])</pre>



<p>Additionally, when we hit the <em>refresh</em> button in MongoDB Compass, we should see the following: </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="358" src="http://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_created_product_atlas_view-1024x358.png" alt="Image shows a screenshot from MongoDB Compass and persisted product with coroutines." class="wp-image-17012580" srcset="https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_created_product_atlas_view-1024x358.png 1024w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_created_product_atlas_view-300x105.png 300w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_created_product_atlas_view-768x269.png 768w, https://blog.codersee.com/wp-content/uploads/2025/02/ktor_mongodb_created_product_atlas_view.png 1410w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>And this proves that not only the Product was saved. But also, the <code>application</code> database and <code>products</code> collection was created by our client automatically. </p>



<h2 class="wp-block-heading" id="h-find-by-id">Find By ID</h2>



<p> Nextly, let&#8217;s implement the function to fetch product by identifier: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findById(id: String): Product? {
    val objectId = ObjectId(id)

    return productCollection.find(
        eq("_id", objectId)
    ).firstOrNull()
}</pre>



<p>This time, we use the <code>find</code> method. And this function returns the <em>FindFlow</em> which is the <em>Flow </em>implementation for find operations. </p>



<p>This function allows us to pass filters as arguments to it. And to get the particular product, we use the <strong>eq </strong>filter. One of the many filters that we can find in <code>com.mongodb.client.model.Filters</code>. We must remember that our identifier is of the <em>ObjectId</em> type, so we create a new instance from our String value. </p>



<p>Lastly, we invoke the <code>firstOrNull</code>&#8211; the terminal operator that returns the first element emitted by the flow and then cancels flow&#8217;s. We leverage the fact that only one element with such an identifier can be found in our database.</p>



<p>So with all of that done, let&#8217;s get back to the <code>Application.kt</code> and test this function: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val found = runBlocking {
    productRepository.findById("67bd62f974edd96bbd59874a")
}

val notFound = runBlocking {
    productRepository.findById("67bd62f974edd96bbd59874b")
}

// Logs: 

// Product(id=67bd62f974edd96bbd59874a, name=Product 1, description=Description 1, price=19.99, category=TOOLS, tags=[EXCLUSIVE, BESTSELLER])

// null</pre>



<p>As we can see, our test proves that <em>findById</em> not only works but also it simply returns null when nothing was found. No unexpected exceptions, etc. </p>



<h3 class="wp-block-heading" id="h-updating-products">Updating Products</h3>



<p>As the next step, let&#8217;s add the function responsible for updating products: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun update(id: String, product: Product): Product? {
    val objectId = ObjectId(id)

    return productCollection.findOneAndReplace(
        filter = eq("_id", objectId),
        replacement = product,
        options = FindOneAndReplaceOptions().returnDocument(ReturnDocument.AFTER)
    )
}</pre>



<p>Again, this function is a suspended function, and again we use the same combination of the <em>eq</em> filter and <em>ObjectId</em> to find the item we are interested in. </p>



<p>The function that we use- <code>findOneAndReplace</code>&#8211; allows us to simply replace the existing document by passing a new version. Nevertheless, by default, this function returns the <strong>object before the update!</strong> And in my opinion, it makes more sense to return the updated versions in this case. And that&#8217;s why we specify the additional option. </p>



<p>As a note: if you would like to update just some fields, then the <code>findOneAndUpdate</code> may be a better choice. </p>



<p>With all of that done, let&#8217;s test our functionality: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val updated = runBlocking {
    productRepository.update(
        id = "67bd62f974edd96bbd59874a",
        product = Product(
            name = "Updated Product 1",
            description = "Updated Description 1",
            price = 20.11,
            category = ProductCategory.FOOD,
            tags = listOf(ProductTag.BESTSELLER)
        )
    )
}

val notUpdated = runBlocking {
    productRepository.update(
        id = "67bd62f974edd96bbd59874b",
        product = Product(
            name = "Updated Product 2",
            description = "Updated Description 3",
            price = 20.11,
            category = ProductCategory.FOOD,
            tags = listOf(ProductTag.BESTSELLER)
        )
    )
}

// Logs: 

// Product(id=67bd62f974edd96bbd59874a, name=Updated Product 1, description=Updated Description 1, price=20.11, category=FOOD, tags=[BESTSELLER])

// null</pre>



<p>As we can see, everything works as expected. Our function returns the <strong>updated</strong> product. And moreover, it does not throw any exceptions when a product is not found! </p>



<h3 class="wp-block-heading" id="h-delete-products">Delete Products</h3>



<p>Nextly, let&#8217;s take a look at how we can remove products from our database: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun deleteById(id: String): Boolean {
    val objectId = ObjectId(id)

    val deleteResult = productCollection.deleteOne(
        eq("_id", objectId)
    )

    return deleteResult.deletedCount == 1L
}</pre>



<p>At this point of our MongoDB coroutines tutorial, I think the code is quite descriptive. We use the same pattern we did previously to find by ID and we utilize the function from <code>DeleteResult</code> to get the count of deleted items. </p>



<p>Of course, given we have only one item with a particular <code>_id</code>, the function returns <em>true</em> only if the count is equal to one. </p>



<p>And again, a small note from my end if you would like to return the deleted product instead, then you can use the <code>findOneAndDelete</code> instead.</p>



<p>I will skip the testing part here, you must trust me 😀</p>



<h3 class="wp-block-heading" id="h-case-insensitive-search-in-mongodb">Case-insensitive Search In MongoDB</h3>



<p>As the last step, I will show you how to utilize the function that we already know (<code>find</code>) to perform a case-insensitive search in MongoDB: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun find(
    title: String,
): Flow&lt;Product> {
    return productCollection.find(
        regex(Product::name.name, title, "i")
    )
}</pre>



<p>As we can see, this time we make use of the <code>regex</code> function, that will add the&#8230; regex filter 😀 And thanks to the <strong>&#8220;i&#8221;</strong> option, the whole search will be case-insensitive.</p>



<p>Additionally, we make use of the <em>name</em> field reference. We could use a simple String value- &#8220;name&#8221;- but thanks to our approach we won&#8217;t need to remember to manually update the name in case of the update. </p>



<p>Lastly, I just wanted to mention here that this is one of the approaches to tackle this issue. According to the Mongo docs, we have also two more options: </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>1. Create a case-insensitive index with a collation strength of 1 or 2, and specify that your query uses the same collation.<br>2. Set the default collation strength of your collection to 1 or 2 when you create it, and do not specify a different collation in your queries and indexes.</p>
</blockquote>



<h3 class="wp-block-heading" id="h-adding-sorting-and-pagination-to-search-results">Adding Sorting and Pagination to Search Results</h3>



<p>Lastly, let&#8217;s make a small adjustment to add pagination and sorting to our logic.</p>



<p>To do so, let&#8217;s implement the <code>Order</code> Enum first:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">enum class Order {
    ASC, DESC
}</pre>



<p>And with that done, let&#8217;s get back to our repository: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun find(
    title: String,
    sortBy: String,
    order: Order,
    limit: Int,
    skip: Int,
): Flow&lt;Product> {
    val sort = when (order) {
        Order.ASC -> ascending(sortBy)
        Order.DESC -> descending(sortBy)
    }

    return productCollection.find(
        regex(Product::name.name, title, "i")
    )
        .sort(sort)
        .limit(limit)
        .skip(skip)
}</pre>



<p>As we can see, our function allows us to pass 4 more arguments during the invocation: <em>sortBy</em>, <em>order</em>, <em>limit</em>, and <em>skip</em>.</p>



<p>So from now on, we can not only perform the search but also set the limit of results, ordering, as well as the order of items.</p>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And that&#8217;s all for this tutorial on how to work with MongoDB and Kotlin coroutines in Ktor. </p>



<p>I hope you enjoyed it, and if you would like to learn more Ktor concepts in a fully hands-on manner, then check out my <a href="https://codersee.com/courses/ktor-server-pro/">course</a>. </p>



<p>Lastly, if you would like to get the whole codebase, then you can find it in <a href="https://github.com/codersee-blog/ktor-mongodb-coroutines" target="_blank" rel="noreferrer noopener">this GitHub repository</a>.</p>



<p></p>
<p>The post <a href="https://blog.codersee.com/mongodb-kotlin-coroutines-ktor/">MongoDB with Kotlin Coroutines in Ktor</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/mongodb-kotlin-coroutines-ktor/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Reactive Programming in Kotlin: A Step-by-Step Guide</title>
		<link>https://blog.codersee.com/reactive-programming-in-kotlin-a-step-by-step-guide/</link>
					<comments>https://blog.codersee.com/reactive-programming-in-kotlin-a-step-by-step-guide/#respond</comments>
		
		<dc:creator><![CDATA[Peter Lantukh]]></dc:creator>
		<pubDate>Thu, 15 Feb 2024 05:00:00 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Reactive Programming]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9508665</guid>

					<description><![CDATA[<p>This article provides a general overview of Reactive Programming and tools available in Kotlin in terms of Reactive Programming.</p>
<p>The post <a href="https://blog.codersee.com/reactive-programming-in-kotlin-a-step-by-step-guide/">Reactive Programming in Kotlin: A Step-by-Step Guide</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this article, we are going to tackle <strong>Reactive Programming in Kotlin</strong>. We will start with what exactly <strong>Reactive Programming</strong> is, how we could use it to our advantage, and what techniques we can use in <strong>Kotlin</strong>. I am going to explain everything in simple terms to make this article <strong>beginner-friendly</strong> (considering you know the basics of Kotlin, of course).</p>



<p>In some <strong>future articles</strong>, we will put that knowledge into action on the <strong>example of the Ktor project</strong>, emphasizing the Reactive approach. So don&#8217;t forget to follow me on <a href="https://www.linkedin.com/in/peter-lantukh/" target="_blank" rel="noreferrer noopener">LinkedIn</a> to not miss out 🙂  </p>



<h2 class="wp-block-heading" id="h-reactive-programming">Reactive Programming</h2>



<p>If you try to search for what <strong>Reactive Programming</strong> is, you will sooner or later find The <strong><a href="https://www.reactivemanifesto.org/" target="_blank" rel="noreferrer noopener">Reactive Manifesto,</a></strong> which is cited by almost everyone. </p>



<p>And in most articles, there will be something like the following diagram:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="501" height="281" src="http://blog.codersee.com/wp-content/uploads/2024/02/ReactiveApproach-1.png" alt="Image presents reactive programming diagram about manifesto: responsive, elastic, resilient, message driven. " class="wp-image-9508673" srcset="https://blog.codersee.com/wp-content/uploads/2024/02/ReactiveApproach-1.png 501w, https://blog.codersee.com/wp-content/uploads/2024/02/ReactiveApproach-1-300x168.png 300w" sizes="auto, (max-width: 501px) 100vw, 501px" /></figure>



<p>For the beginner, all of these definitions and explanations are <strong>vague and unclear</strong>. It is absolutely possible to learn it and speak about it, for example, in an interview with zero understanding whatsoever. Instead, <strong>let&#8217;s connect it to concepts that are present in software development</strong>, and don&#8217;t worry if you are not familiar with them. </p>



<p>Let&#8217;s take a look at another diagram that represents the concepts:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="401" height="181" src="http://blog.codersee.com/wp-content/uploads/2024/02/ReactiveApproach2-1.png" alt="Image presents diagram with observer and interator pattern." class="wp-image-9508674" srcset="https://blog.codersee.com/wp-content/uploads/2024/02/ReactiveApproach2-1.png 401w, https://blog.codersee.com/wp-content/uploads/2024/02/ReactiveApproach2-1-300x135.png 300w" sizes="auto, (max-width: 401px) 100vw, 401px" /></figure>



<p>The key concepts in the <strong>Observer Pattern</strong> are &#8220;<strong>subjects</strong>&#8221; and &#8220;<strong>observers</strong>&#8220;. When a subject&#8217;s <strong>state changes</strong>, it <strong>notifies</strong> all its observers, allowing them to react accordingly.</p>



<p>The <strong>Iterator Pattern</strong> introduces a way to access elements of some object, most likely a collection, sequentially without exposing its internal implementation.</p>



<p>And as a cherry on top, Reactive Programming is tight with <strong>Functional Programming</strong> so, in essence, let&#8217;s define what Reactive Programming is in these terms. Reactive Programming leverages the <strong>Observer&#8217;s one-to-many notification</strong> and the <strong>Iterator&#8217;s sequential access</strong>, but extends them to handle continuous data flows and <strong>asynchronous interactions</strong> without defining &#8220;what&#8221; to do with data but &#8220;how&#8221; to iterate.</p>



<h2 class="wp-block-heading" id="h-streams">Streams</h2>



<p>All mentioned before leads us to another core concept: <strong>Streams</strong>. If you are familiar with the Flows, it is basically them, if not we&#8217;ll cover them later anyway. So, a Stream is a <strong>sequence of data objects</strong> that can be consumed and processed asynchronously. What is more, you can also merge, filter, combine, and transform them to handle data successfully.</p>



<p>Now let&#8217;s check what Kotlin can offer in terms of the Reactive Approach. We will start with asynchronicity, and the best solution for this is Coroutines and especially Flows. But before that, let&#8217;s discuss types of streams.</p>



<h2 class="wp-block-heading" id="h-cold-and-hot-streams">&#8220;Cold&#8221; and &#8220;Hot&#8221; Streams</h2>



<p>In terms of emitting data, we have <strong>two types of streams</strong>. On the one hand, &#8220;<strong>cold</strong>&#8221; streams are streams that can only emit data when there is someone who could consume it, in other words, if there is any <strong>observer attached</strong>. This basically means that no data would be missed and the whole chain of the items consumed. </p>



<p>On the other hand, we have &#8220;<strong>hot</strong>&#8221; streams. They are <strong>not dependent on any observable</strong> attached and start emitting items as soon as they are created. And here is the key difference, you could &#8220;<strong>miss</strong>&#8221; values using &#8220;hot&#8221; streams if they are not handled carefully. </p>



<h2 class="wp-block-heading" id="h-kotlin-coroutines">Kotlin Coroutines </h2>



<p>Quick dive into Coroutines basics, and then we will, Coroutines allow us to create an <strong>asynchronous code execution</strong> just like threads, but they are <strong>not bound to any particular thread</strong> and without callbacks.</p>



<p>Now for the real part, the Reactive Programming Coroutines library can offer 3 options: </p>



<ul class="wp-block-list">
<li>Channels</li>



<li>StateFlow</li>



<li>SharedFlow</li>
</ul>



<p>Both StateFlow and SharedFlow are evolutions of the <strong>Flow</strong> which is generally a Stream I&#8217;ve mentioned before. Flow represents a <strong>sequence of values that can be computed asynchronously</strong>. But firstly, let&#8217;s start from Channels.</p>



<h2 class="wp-block-heading" id="h-channels">Channels</h2>



<p>The first notable object is <strong>Chanel</strong>. As documentation states, Chanel provides communication between coroutines. But in terms of our topic, Chanel is a &#8220;hot&#8221; Stream in which <strong>each individual value could consume only one observer</strong>. </p>



<p>Nevertheless, it can have more the one observer, but the values would be delivered to the first awaited. If there are many observers that wait for the value to be delivered, some collectors will get suspended. Now let&#8217;s check a simple code example: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

suspend fun fetchStockPrice(): Double {
    delay(1000) // Simulate API call delay
    return Math.random() * 100
}

fun main() = runBlocking {
    // Create a Chanel to hold stock prices
    val stockPrices = Channel&lt;Double>()

    // Launch a coroutine to fetch prices every second
    launch {
        while (isActive) {
            val price = fetchStockPrice()
            stockPrices.send(price)
            delay(1000)
        }
    }

    // Launch a coroutine to consume and display prices
    launch {
        for (price in stockPrices) {
            println("Current Stock Price: $$price")
        }
    }

    delay(Long.MAX_VALUE)
}</pre>



<p>This example simulates a stock price ticker application that fetches prices from an API in real time and displays them to the user. </p>



<p>We used Channel to handle the asynchronous data flow and transfer data from one Coroutine to another!</p>



<h2 class="wp-block-heading" id="h-sharedflow">SharedFlow</h2>



<p>The SharedFlow is a Stream in all of its glory. </p>



<p>It is a <strong>hot</strong> stream, that can have <strong>multiple numbers of observers.</strong> We can check it out with the following code example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

data class Item(val name: String, val price: Double)

fun main() = runBlocking {
    // SharedFlow to hold the cart items
    val cartItems = MutableSharedFlow&lt;List&lt;Item>>()

    // Launch a coroutine to print the cart on SharedFlow
    launch {
        cartItems.collect { items ->
            println("Cart Updated: $items")
        }
    }

    // Launch another coroutine to trigger order confirmation when the cart is full
    launch {
        cartItems.filter { it.size >= 3 } // Filter for 3 or more items
            .onEach { println("Order Confirmation triggered!") }
            .launchIn(this)
    }

    // Launch a coroutine to simulate adding items to the cart
    launch {
        var updatedItems = listOf(Item("Apple", 1.50))
        cartItems.emit(updatedItems)
        delay(1000)
        updatedItems = updatedItems + Item("Milk", 2.00)
        cartItems.emit(updatedItems)
        delay(1000)
        updatedItems = updatedItems + Item("Bread", 3.00)
        cartItems.emit(updatedItems)
    }

    delay(Long.MAX_VALUE)
}</pre>



<p>In the example above, we created a shopping cart application where multiple components need to react to changes in the cart items. </p>



<p>SharedFlow provides a centralized way to share updates efficiently. And we can witness multiple observers at the same time.</p>



<h2 class="wp-block-heading" id="h-stateflow">StateFlow</h2>



<p>The StateFlow is similar to SharedFlow. However, it is a somewhat <strong>cold</strong> stream because it <strong>requires some initial value</strong> on creation, and it <strong>always holds a value</strong>. </p>



<p>This basically means that it always has a value to observe. Here&#8217;s a good example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

enum class PlayerState {
    Playing,
    Paused,
    Stopped
}

fun main() = runBlocking {
    // StateFlow to hold the current player state
    val playerState = MutableStateFlow(PlayerState.Stopped)

    // Launch a coroutine to print state based on StateFlow
    launch {
        playerState.collect { state ->
            println("Player State: $state")
        }
    }

    // Launch a coroutine to simulate user actions
    launch {
        // Play/pause/stop actions update the state
        playerState.emit(PlayerState.Playing)
        delay(2000)
        playerState.emit(PlayerState.Paused)
        delay(1000)
        playerState.emit(PlayerState.Stopped)
    }

    delay(Long.MAX_VALUE)
}</pre>



<p>For this example, we use a music player application where the current playing state needs to be tracked. StateFlow provides a single source of truth for this state, with an initial value.</p>



<h2 class="wp-block-heading" id="h-other-reactive-options-available">Other Reactive options available</h2>



<p>The most popular alternatives are <strong>ReactiveX libraries</strong>. The main competitor is RxJava for Java basically and it&#8217;s widely used especially in <strong>Android Development</strong>. Unfortunately, <strong>RxKotlin</strong> has almost zero popularity these days due to its extensive RxJava presence. </p>



<p>RxJava provides extensive tools for Reactive programming, but due to its limited integration with <strong>Kotlin Coroutines</strong>, I recommend using Coroutines but keep in mind that this powerful tool is also available.</p>



<p>There are also lots of libraries tightly connected to <strong>Spring Boot</strong>. There are <strong>Spring WebFlux, and Project Reactor.</strong> They are provided tools in applications for building reactive systems in <strong>JVM Backend Development,</strong> but not that popular in Kotlin. </p>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And that’s all for this article about Reactive Programming in Kotlin with Coroutines and Flows.</p>



<p>In the upcoming articles, we will get back to this topic and learn how to apply this knowledge with Ktor, so don’t forget to join the free newsletter to not miss it!</p>



<p>Lastly, if you would like to learn more about Flows, then you can find lots of useful information on the <a href="https://kotlinlang.org/docs/flow.html">official documentation</a> of Kotlin.</p>
<p>The post <a href="https://blog.codersee.com/reactive-programming-in-kotlin-a-step-by-step-guide/">Reactive Programming in Kotlin: A Step-by-Step Guide</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/reactive-programming-in-kotlin-a-step-by-step-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot 3 Kotlin Router DSL</title>
		<link>https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/</link>
					<comments>https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 21 Mar 2023 07:00:45 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Spring WebFlux]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=6004428</guid>

					<description><![CDATA[<p>In this practical tutorial, I will show you how to expose web endpoints using Spring Boot 3 and Kotlin router DSL (functional style).</p>
<p>The post <a href="https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/">Spring Boot 3 Kotlin Router DSL</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Hello friend! 🙂 Welcome to my next practical tutorial, in which I will show you how to expose web endpoints using <strong>Spring Boot 3</strong> and <strong>Kotlin router DSL</strong> (aka- functional style).</p>



<p>Basically, the Kotlin router DSL comes in 3 variants:</p>



<ul class="wp-block-list">
<li><em>WebMvc.fn DSL</em> using <code class="EnlighterJSRAW" data-enlighter-language="raw">router { }</code> &#8211; which we can use when working with a &#8220;standard&#8221; MVC Spring Project,</li>



<li><em>WebFlux.fn Reactive DSL</em> with <code class="EnlighterJSRAW" data-enlighter-language="raw">router { }</code> &#8211; used when working with a reactive-stack framework- Spring Webflux,</li>



<li><em>WebFlux.fn Coroutines DSL</em> with <code class="EnlighterJSRAW" data-enlighter-language="raw">coRouter { }</code> &#8211; as the name suggests- the one we will use when working with coroutines.</li>
</ul>



<p>And although in this article, we will make use of the coroutine-based REST API implemented in &#8220;<a href="https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/">Reactive REST API With Spring, Kotlin, and Coroutines</a>&#8220;, the knowledge you&#8217;re gonna gain today is universal and will work regardless of the implementation.</p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<p></p></div>


<a href="https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FfS23KwIBqfc%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-2-project-configuration">2. Project Configuration</h2>



<p>As I mentioned in the introduction, we will reuse the already implemented API and rewrite the @RestController approach using the Spring Boot Kotlin DSL router.</p>


<p>[elementor-template id=&#8221;9007393&#8243;]</p>



<p>So, as the first step, let&#8217;s clone this <a href="https://github.com/codersee-blog/spring-boot-3-kotlin-coroutines" target="_blank" rel="noopener">GitHub repository.</a></p>



<p>When we navigate to the <code class="EnlighterJSRAW" data-enlighter-language="raw">controller</code> package, we will see that the project contains 3 controllers:</p>



<ul class="wp-block-list">
<li>UserController</li>



<li>SearchController</li>



<li>CompanyController</li>
</ul>



<p>And for the purpose of this tutorial, we will focus on the API responsible for users management:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestController
@RequestMapping("/api/users")
class UserController(
    private val userService: UserService
) {

  @PostMapping
  suspend fun createUser(@RequestBody userRequest: UserRequest): UserResponse =
    userService.saveUser(
        user = userRequest.toModel()
    )
      ?.toResponse()
      ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error during user creation.")

  @GetMapping
  suspend fun findUsers(
    @RequestParam("name", required = false) name: String?
  ): Flow {
    val users = name?.let { userService.findAllUsersByNameLike(name) }
      ?: userService.findAllUsers()

    return users.map(User::toResponse)
  }

  @GetMapping("/{id}")
  suspend fun findUserById(
    @PathVariable id: Long
  ): UserResponse =
    userService.findUserById(id)
      ?.let(User::toResponse)
      ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")

  @DeleteMapping("/{id}")
  suspend fun deleteUserById(
    @PathVariable id: Long
  ) {
    userService.deleteUserById(id)
  }

  @PutMapping("/{id}")
  suspend fun updateUser(
    @PathVariable id: Long,
    @RequestBody userRequest: UserRequest
  ): UserResponse =
    userService.updateUser(
      id = id,
      requestedUser = userRequest.toModel()
    )
      .toResponse()
}

private fun UserRequest.toModel(): User =
  User(
    email = this.email,
    name = this.name,
    age = this.age,
    companyId = this.companyId
  )

fun User.toResponse(): UserResponse =
  UserResponse(
    id = this.id!!,
    email = this.email,
    name = this.name,
    age = this.age
  )
</pre>



<h2 class="wp-block-heading" id="h-3-convert-usercontroller-to-handler">3. Convert UserController To Handler</h2>



<p>Before we will start working with Spring Boot Kotlin DSL, let&#8217;s make a few adjustments.</p>



<p>Firstly, let&#8217;s add a new package called <code class="EnlighterJSRAW" data-enlighter-language="raw">handler</code>.</p>



<p>Then, let&#8217;s remove all annotations inside the class and mark the <em>UserHandler</em> with <em>@Component</em>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Component
class UserHandler(
    private val userService: UserService
) {

  suspend fun createUser(userRequest: UserRequest): UserResponse =
    userService.saveUser(
      user = userRequest.toModel()
    )
      ?.toResponse()
      ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error during user creation.")

  suspend fun findUsers(
    name: String?
  ): Flow {
    val users = name?.let { userService.findAllUsersByNameLike(name) }
      ?: userService.findAllUsers()

    return users.map(User::toResponse)
  }

  suspend fun findUserById(
    id: Long
  ): UserResponse =
    userService.findUserById(id)
      ?.let(User::toResponse)
      ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")

  suspend fun deleteUserById(
    id: Long
  ) {
    userService.deleteUserById(id)
  }

  suspend fun updateUser(
    id: Long,
    userRequest: UserRequest
  ): UserResponse =
    userService.updateUser(
      id = id,
      requestedUser = userRequest.toModel()
    )
      .toResponse()
}
</pre>



<h2 class="wp-block-heading" id="h-4-implement-coroutines-router-with-kotlin-dsl">4. Implement Coroutines router with Kotlin DSL</h2>



<p>With all of that being done, let&#8217;s create a new class <em>Config</em> inside the <code class="EnlighterJSRAW" data-enlighter-language="raw">config</code> package:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Configuration
class Config {

  @Bean
  fun router(
    userHandler: UserHandler
  ) = coRouter {
    accept(MediaType.APPLICATION_JSON).nest {

      "/api/users".nest {
        POST("", userHandler::createUser)
        GET("", userHandler::findUsers)
        GET("/{id}", userHandler::findUserById)
        DELETE("/{id}", userHandler::deleteUserById)
        PUT("/{id}", userHandler::updateUser)
      }

    }
  }

}
</pre>



<p>As I mentioned in the beginning when working with coroutines, we will create a <strong>RouterFunction using coRouter{ }</strong>. Nevertheless, when working with MVC or Spring WebFlux, then the choice would be the <strong>router {}</strong>.</p>



<p>As we can see, the <strong>nest {}</strong> function allows us to structure routing in a neat and readable manner.</p>



<p>Let&#8217;s take a look at the following example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">"/api/v1".nest {
  "/whatever".nest {
    "/sub-whatever".nest {
      // whatever
    }
  }
}

"/api/v2".nest {
  // another handlers
}
</pre>



<p>This way, we can manage versioning in one place.</p>



<p>Nevertheless, let&#8217;s get back to our user handlers:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">POST("", userHandler::createUser)
GET("", userHandler::findUsers)
GET("/{id}", userHandler::findUserById)
DELETE("/{id}", userHandler::deleteUserById)
PUT("/{id}", userHandler::updateUser)
</pre>



<p>At this point, our application won&#8217;t compile, because of one, important thing- <strong>handler functions must take only one parameter of the ServerRequest type</strong>.</p>



<p>So in order to fix the app, we will have to update our Spring controller for functional routing.</p>



<h2 class="wp-block-heading" id="h-5-update-post-endpoint">5. Update POST Endpoint</h2>



<p>So as the first step, let&#8217;s make the necessary adjustments to the <code class="EnlighterJSRAW" data-enlighter-language="raw">createUser</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun createUser(request: ServerRequest): ServerResponse {
  val userRequest = request.awaitBody(UserRequest::class)

  val savedUserResponse = userService.saveUser(
    user = userRequest.toModel()
  )
    ?.toResponse()
    ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error during user creation.")

  return ServerResponse.ok()
    .bodyValueAndAwait(savedUserResponse)
}

// Before:


@PostMapping
suspend fun createUser(@RequestBody userRequest: UserRequest): UserResponse =
  userService.saveUser(
    user = userRequest.toModel()
  )
    ?.toResponse()
    ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error during user creation.")
</pre>



<p>As we can see, instead of binding the JSON payload to the UserRequest instance with an annotation, we have to do it manually with <code class="EnlighterJSRAW" data-enlighter-language="raw">.awaitBody()</code>.</p>



<p>Whatsoever, the return type changes to <strong>ServerResponse</strong>, which we have to create manually.</p>



<p>And although the final choice is up to you, instead of throwing the ResponseStatusException, we can compose the HTTP error response on our own:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun createUser(request: ServerRequest): ServerResponse {
  val userRequest = request.awaitBody(UserRequest::class)

  return userService.saveUser(
    user = userRequest.toModel()
  )
    ?.toResponse()
    ?.let { response ->
      ServerResponse.ok()
        .bodyValueAndAwait(response)
    }
    ?: ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
      .buildAndAwait()
}
</pre>



<h2 class="wp-block-heading" id="h-6-migrate-get-all-users">6. Migrate GET All Users</h2>



<p>Nextly, let&#8217;s migrate the <code class="EnlighterJSRAW" data-enlighter-language="raw">findUsers()</code> function and learn how to read query parameters:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findUsers(
  request: ServerRequest
): ServerResponse {
  val users = request.queryParamOrNull("name")
    ?.let { name -> userService.findAllUsersByNameLike(name) }
    ?: userService.findAllUsers()

  val usersResponse = users.map(User::toResponse)

  return ServerResponse.ok()
    .bodyAndAwait(usersResponse)
}

// Before:

@GetMapping
suspend fun findUsers(
  @RequestParam("name", required = false) name: String?
): Flow {
  val users = name?.let { userService.findAllUsersByNameLike(name) }
    ?: userService.findAllUsers()

  return users.map(User::toResponse)
} 
</pre>



<p>This time, in order to read a particular query parameter, we can use the <code class="EnlighterJSRAW" data-enlighter-language="raw">queryParamOrNull(String)</code>. However, the ServerRequest interface comes with two, additional functions, which we could use here:</p>



<ul class="wp-block-list">
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">queryParam(String)</code>, which returns the <em>Optional</em>,</li>



<li>and <code class="EnlighterJSRAW" data-enlighter-language="raw">queryParams()</code> returning an instance of <em>MultiValueMap&lt;String, String&gt;</em> with all parameters.</li>
</ul>



<p>And just, like previously we compose a ServerResponse instance, but this time using the <code class="EnlighterJSRAW" data-enlighter-language="raw">bodyAndAwait()</code>, which takes a <em>Flow</em> as an argument.</p>



<h2 class="wp-block-heading" id="h-7-get-user-by-id">7. GET User By Id</h2>



<p>As the next example in our Spring Boot Kotlin DSL project, let&#8217;s rewrite the <code class="EnlighterJSRAW" data-enlighter-language="raw">findUserById()</code> and see how we can read a <strong>path variable</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findUserById(
  request: ServerRequest
): ServerResponse {
  val id = request.pathVariable("id").toLong()

  val userResponse = userService.findUserById(id)
    ?.let(User::toResponse)
    ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")

  return ServerResponse.ok()
    .bodyValueAndAwait(userResponse)
}

// Before:

@GetMapping("/{id}")
suspend fun findUserById(
  @PathVariable id: Long
): UserResponse =
  userService.findUserById(id)
    ?.let(User::toResponse)
    ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")
</pre>



<p>As we can see, in order to read the path variable, we have to use the <code class="EnlighterJSRAW" data-enlighter-language="raw">pathVariable(String)</code> (or alternatively, <code class="EnlighterJSRAW" data-enlighter-language="raw">pathVariables()</code>). Unfortunately, this function cannot be parametrized and we have to take care of Long conversions manually.</p>



<h2 class="wp-block-heading" id="h-8-delete-endpoint">8. DELETE Endpoint</h2>



<p>Following, let&#8217;s update the <code class="EnlighterJSRAW" data-enlighter-language="raw">deleteUserById()</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun deleteUserById(
  request: ServerRequest
): ServerResponse {
  val id = request.pathVariable("id").toLong()

  userService.deleteUserById(id)

  return ServerResponse.noContent()
    .buildAndAwait()
}

// Before: 

@DeleteMapping("/{id}")
suspend fun deleteUserById(
  @PathVariable id: Long
) {
  userService.deleteUserById(id)
}
</pre>



<p>And this time, instead of returning anything in the response payload, we make use of the <code class="EnlighterJSRAW" data-enlighter-language="raw">noContent()</code> along with <code class="EnlighterJSRAW" data-enlighter-language="raw">buildAndAwait()</code> to return a bodiless entity.</p>



<h2 class="wp-block-heading" id="h-9-user-update-with-put">9. User Update With PUT</h2>



<p>Lastly, let&#8217;s make the necessary adjustments to the <code class="EnlighterJSRAW" data-enlighter-language="raw">updateUser()</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun updateUser(
  request: ServerRequest
): ServerResponse {
  val id = request.pathVariable("id").toLong()
  val userRequest = request.awaitBody(UserRequest::class)

  val userResponse = userService.updateUser(
    id = id,
    requestedUser = userRequest.toModel()
  ).toResponse()

  return ServerResponse.ok()
    .bodyValueAndAwait(userResponse)
}

// Before:

@PutMapping("/{id}")
suspend fun updateUser(
  @PathVariable id: Long,
  @RequestBody userRequest: UserRequest
): UserResponse =
  userService.updateUser(
    id = id,
    requestedUser = userRequest.toModel()
  )
    .toResponse()
</pre>



<p>As we can see, nothing new shows up in this example.</p>



<h2 class="wp-block-heading" id="h-10-testing-and-homework">10. Testing And Homework</h2>



<p>With all of that being done, we can finally run our application and verify whether handlers are working, as expected.</p>



<p>Your homework will be to:</p>



<ol class="wp-block-list">
<li>Test whether the routing works fine after we converter our Spring controller to the functional style.</li>



<li>Refactor the <em>CompanyController</em> and <em>SearchController</em> classes in a similar manner.</li>
</ol>



<p>As a bonus, right here you can find a <a href="https://drive.google.com/file/d/1xq3njZk2oGwHQGZkTFf05VwHr1pdsJJE/view?usp=sharing" target="_blank" rel="noopener">Postman collection</a>, which you can use for testing.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Note: If you would like to see the solution, then check out the <a href="https://github.com/codersee-blog/spring-boot-3-kotlin-coroutines/tree/router-dsl" target="_blank" rel="noopener">router-dsl branch</a> in my GitHub repo.</p>
</blockquote>



<h2 class="wp-block-heading" id="h-11-spring-boot-3-with-kotlin-dsl-summary">11. Spring Boot 3 With Kotlin DSL Summary</h2>



<p>And that&#8217;s all for this tutorial, in which we have learned how to expose web endpoints using <strong>Spring Boot 3</strong> and <strong>Kotlin router DSL</strong> (aka- functional style).</p>



<p>Hope you enjoyed this content, and if so, then please <strong>reach out in the comments section</strong>.</p>



<p>Have a great week!</p>
<p>The post <a href="https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/">Spring Boot 3 Kotlin Router DSL</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Spring WebClient With Kotlin Coroutines</title>
		<link>https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/</link>
					<comments>https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 07 Mar 2023 07:00:42 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Spring WebFlux]]></category>
		<category><![CDATA[WebClient]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=6004406</guid>

					<description><![CDATA[<p>In this, revisited article I will show you everything you need to know when working with Spring WebClient and Kotlin coroutines.</p>
<p>The post <a href="https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/">Spring WebClient With Kotlin Coroutines</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Welcome to my next article, in which I will show you everything you need to know when working with <strong>Spring WebClient and Kotlin coroutines</strong>.</p>



<p>To be on the same page- this article will be a coroutine-focused extension of my other blog post about <a href="https://blog.codersee.com/spring-5-webclient-with-spring-boot/" target="_blank" rel="noopener">Spring 5 WebClient with Spring Boot</a>. So, instead of duplicating the content, which works exactly the same regardless of whether we pick the Reactor or coroutines implementation, I will focus on response handling. Nevertheless, if you are interested in other features, like request bodies, headers, and filter implementation, then I recommend checking out that article, as well.</p>



<p>With that being said, let&#8217;s get to work 🙂</p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<p></p></div>


<a href="https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FS8ie6zyJHsw%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-2-api-specification">2. API Specification</h2>



<p>Before I show you how to implement WebClient with Kotlin coroutines, let me quickly describe the API we are about to query.</p>



<p>Basically, we will be using 3 endpoints in order to:</p>



<ul class="wp-block-list">
<li>fetch a list of all users,</li>



<li>get user by its identifier,</li>



<li>and delete a particular user by id.</li>
</ul>



<p>And to better visualize, let&#8217;s take a look at the API &#8220;contract&#8221;:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">GET http://localhost:8090/users 

# Example response:
[
  {
    "id": 1,
    "first_name": "Robert",
    "last_name": "Smith"
  },
  {
    "id": 2,
    "first_name": "Mary",
    "last_name": "Jones"
  }
...
]

GET http://localhost:8090/users/1

# Example successful response body:
{
  "id": 1,
  "first_name": "Robert",
  "last_name": "Smith"
}

# If the user is not found, then the API returns 404 NOT FOUND

DELETE http://localhost:8090/users/1

# Responds 204 No Content with empty body</pre>


<p>[elementor-template id=&#8221;9007393&#8243;]</p>



<h2 class="wp-block-heading" id="h-3-configure-spring-webclient">3. Configure Spring WebClient</h2>



<p>And although the Spring WebClient configuration does not differ when working with coroutines, let&#8217;s take a look at the config class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Configuration
class Config {

  @Bean
  fun webClient(builder: WebClient.Builder): WebClient =
      builder
        .baseUrl("http://localhost:8090")
        .build()
}
</pre>



<p>As we can see, with this config we define a new WebClient bean and instruct that a base URL for our requests is <code class="EnlighterJSRAW" data-enlighter-language="raw">http://localhost:8090</code>.</p>



<h2 class="wp-block-heading" id="h-4-implement-userresponse">4. Implement UserResponse</h2>



<p>Nextly, let&#8217;s add the UserResponse class to our codebase:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class UserResponse(
  val id: Long,
  @JsonProperty("first_name") val firstName: String,
  @JsonProperty("last_name") val lastName: String
)
</pre>



<p>And this class will be responsible for serializing responses from the external API.</p>



<h2 class="wp-block-heading" id="h-5-spring-webclient-with-kotlin-coroutines">5. Spring WebClient With Kotlin Coroutines</h2>



<p>As the next step, we can finally implement the UserApiService and start querying.</p>



<p>Of course, let&#8217;s inject the WebClient before heading to the next steps:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Service
class UserApiService(
  private val webClient: WebClient
) {

}
</pre>



<h3 class="wp-block-heading" id="h-5-1-obtaining-response-body-with-awaitbody">5.1 Obtaining Response Body With awaitBody()</h3>



<p>Firstly, let&#8217;s learn how to fetch a list of users:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findAllUsers(): List&lt;UserResponse> =
  webClient.get()
    .uri("/users")
    .retrieve()
    .awaitBody&lt;List&lt;UserResponse>>()</pre>



<p>Well, we have to remember that the <code class="EnlighterJSRAW" data-enlighter-language="generic">awaitBody()</code> is a suspend function- and that&#8217;s the reason why our function is defined as a suspend, as well. Moreover, we have to define the type of response we are expecting (<code class="EnlighterJSRAW" data-enlighter-language="generic">List&lt;UserResponse&gt;</code> in our case). Of course, it&#8217;s optional if we already defined a return type explicitly for our function.</p>



<h3 class="wp-block-heading" id="h-5-2-awaitbodyornull">5.2 awaitBodyOrNull()</h3>



<p>Additionally, we can make use of another variant, <code class="EnlighterJSRAW" data-enlighter-language="raw">awaitBodyOrNull()</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findUserById(id: Long): UserResponse? =
  webClient.get()
    .uri("/users/$id")
    .retrieve()
    .awaitBodyOrNull&lt;UserResponse>()</pre>



<p>This time, if the Mono completes without a value, a null is returned.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nevertheless, please keep in mind that by default when using retrieve() 4xx and 5xx responses result in a WebClientResponseException. Later, I will show you how to customize this behavior using onStatus().</p>
</blockquote>



<h3 class="wp-block-heading" id="h-5-3-return-user-list-as-a-flow">5.3 Return User List As A Flow</h3>



<p>As the next step, let&#8217;s learn how to transform our publisher into Flow:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun findAllUsersFlow(): Flow&lt;UserResponse> =
  webClient.get()
    .uri("/users")
    .retrieve()
    .bodyToFlow&lt;UserResponse>()</pre>



<p>This time, instead of converting users&#8217; responses into a List, we invoke the <code class="EnlighterJSRAW" data-enlighter-language="raw">.bodyToFlow&lt;UserResponse&gt;()</code>, which underneath transforms a <code class="EnlighterJSRAW" data-enlighter-language="raw">Flux&lt;UserResponse&gt;</code> into the Flow.</p>



<h3 class="wp-block-heading" id="h-5-4-webclient-retrieve-vs-exchange">5.4 WebClient retrieve vs exchange</h3>



<p>Well, although I promised not to cover things twice, I believe it&#8217;s important to say a couple of words here.</p>



<p>The main difference between <code class="EnlighterJSRAW" data-enlighter-language="raw">retrieve()</code> and <code class="EnlighterJSRAW" data-enlighter-language="raw">exchange()</code> methods is that the <code class="EnlighterJSRAW" data-enlighter-language="raw">exchange()</code> returns additional HTTP information, like headers and status. <strong>Nevertheless</strong>, when using it, <strong>it is our responsibility to handle all response cases to avoid memory leaks!&nbsp;</strong>And because of that, the <code class="EnlighterJSRAW" data-enlighter-language="raw">exchange()</code> was deprecated in Spring 5.3 and we should rather use <code class="EnlighterJSRAW" data-enlighter-language="raw">exchangeToMono(Function)</code> and <code class="EnlighterJSRAW" data-enlighter-language="raw">exchangeToFlux(Function)</code>(of course, if the <code class="EnlighterJSRAW" data-enlighter-language="raw">retrieve()</code> is not sufficient for our needs).</p>



<p>When working with Spring WebClient and Kotlin coroutines, we can make use of the <code class="EnlighterJSRAW" data-enlighter-language="raw">awaitExchange</code> and <code class="EnlighterJSRAW" data-enlighter-language="raw">exchangeToFlow</code> functions.</p>



<h3 class="wp-block-heading" id="h-5-5-awaitexchange">5.5 awaitExchange()</h3>



<p>With that being said, let&#8217;s implement another function using <strong>awaitExchange</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findAllUsersUsingExchange(): List&lt;UserResponse> =
  webClient.get()
    .uri("/users")
    .awaitExchange { clientResponse ->
      val headers = clientResponse.headers().asHttpHeaders()
      logger.info("Received response from users API. Headers: $headers")
      clientResponse.awaitBody&lt;List&lt;UserResponse>>()
    }</pre>



<p>As we can see, this function can be a good choice if we would like to access additional response information (like headers in our case) and perform additional logic based on them.</p>



<h3 class="wp-block-heading" id="h-5-6-exchangetoflow">5.6 exchangeToFlow()</h3>



<p>On the other hand, if we would like to return the Flow, then we must choose <strong>exchangeToFlow</strong> variant:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun findAllUsersFlowUsingExchange(): Flow&lt;UserResponse> =
  webClient.get()
    .uri("/users")
    .exchangeToFlow { clientResponse ->
      val headers = clientResponse.headers().asHttpHeaders()
      logger.info("Received response from users API. Headers: $headers")
      clientResponse.bodyToFlow&lt;UserResponse>()
    }</pre>



<h3 class="wp-block-heading" id="h-5-7-work-with-bodiless">5.7 Work With Bodiless</h3>



<p>Sometimes, the REST API endpoints do not return any response body, which is usually indicated by the 204 No Content status code.</p>



<p>In such a case we can either choose awaitBody and pass the Unit type, or awaitBodilessEntity:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun deleteUserById(id: Long): Unit =
  webClient.delete()
    .uri("/users/$id")
    .retrieve()
    .awaitBody&lt;Unit>()

suspend fun deleteUserById(id: Long): ResponseEntity&lt;Void> =
  webClient.delete()
    .uri("/users/$id")
    .retrieve()
    .awaitBodilessEntity()</pre>



<p>As we can see, depending on our needs we can either simply return the Unit or the ResponseEntity instance.</p>



<h3 class="wp-block-heading" id="h-5-8-handling-errors">5.8 Handling Errors</h3>



<p>And although the last example does not differ when working with WebClient and Kotlin coroutines, I feel obliged to show how we can handle API error status codes.</p>



<p>As I mentioned previously, by default all 4xx and 5xx response status codes cause WebClientResponseException to be thrown. And if we would like to alter this behavior, Spring WebFlux comes with a useful <code class="EnlighterJSRAW" data-enlighter-language="raw">onStatus</code> method for that:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">suspend fun findUserByIdNotFoundHandling(id: Long): UserResponse =
  webClient.get()
    .uri("/users/$id")
    .retrieve()
    .onStatus({ responseStatus ->
      responseStatus == HttpStatus.NOT_FOUND
    }) { throw ResponseStatusException(HttpStatus.NOT_FOUND) }
    .awaitBody&lt;UserResponse>()</pre>



<p>The <code class="EnlighterJSRAW" data-enlighter-language="raw">onStatus</code> takes two parameters: the predicate and a function. In our example, each 404 Not Found response from the external API will be translated to ResponseStatusException with the same HttpStatus.</p>



<h2 class="wp-block-heading" id="h-6-spring-webclient-with-kotlin-coroutines-summary">6. Spring WebClient With Kotlin Coroutines Summary</h2>



<p>And that&#8217;s all for this article. Together, we&#8217;ve learned how easily we can implement a Spring WebClient with Kotlin coroutines using built-in features.</p>



<p>As always, you can find the example source code in this <a href="https://github.com/codersee-blog/spring-webclient-kotlin-coroutines" target="_blank" rel="noopener">GitHub repository</a> and I will be thankful if you would like to share some feedback with me right here, in the comments section.</p>
<p>The post <a href="https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/">Spring WebClient With Kotlin Coroutines</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Reactive REST API With Spring, Kotlin, and Coroutines</title>
		<link>https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/</link>
					<comments>https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Thu, 02 Mar 2023 07:00:00 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Coroutines]]></category>
		<category><![CDATA[Spring WebFlux]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=6004383</guid>

					<description><![CDATA[<p>In this practical guide, I will show you how to create a reactive REST API using Spring, Kotlin, coroutines, and Kotlin Flows.</p>
<p>The post <a href="https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/">Reactive REST API With Spring, Kotlin, and Coroutines</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Hello friend! In this, practical step-by-step guide, I will teach you how to create a reactive <strong>REST API using Spring, Kotlin, coroutines, and Kotlin Flows</strong> entirely from scratch.</p>



<p>And although Spring internally uses Reactor implementation, coroutines provide a more straightforward and natural way of writing asynchronous, non-blocking code. Thanks to this, we can enjoy the benefits of a non-blocking code without <span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">compromising the readability of the code (which might become an issue when using Project Reactor in more mature and complex projects).</span></span></span></p>



<p>At the end of this tutorial, you will know precisely how to:</p>



<ul class="wp-block-list">
<li>set up a <strong>Spring Boot 3</strong> project to work with <strong>Kotlin coroutines</strong>,</li>



<li>run a <strong>PostgreSQL</strong> instance using Docker,</li>



<li>create an example <strong>database and a schema</strong>,</li>



<li>query and persist data using <strong>R2DBC</strong> and <strong>CoroutineCrudRepository</strong>,</li>



<li>expose reactive REST API with <strong>coroutines</strong> and <strong>Kotlin Flows</strong>.</li>
</ul>



<p>So, without any further ado, let&#8217;s get to work 🙂</p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<p></p></div>


<a href="https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FORPWK0NSPiw%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-2-postgresql-db">2. PostgreSQL DB</h2>



<p>As the first step, let&#8217;s learn how to set up a fresh PostgreSQL instance using Docker and populate it with the necessary data. Of course, feel free to skip step 2.1 if you already have some development database installed.</p>



<h3 class="wp-block-heading" id="h-2-1-start-a-postgres-instance">2.1 Start a Postgres Instance</h3>



<p>In order to start a fresh instance, let&#8217;s navigate to the terminal and specify the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">docker run --name some-postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres</pre>



<p>After that, let&#8217;s wait a while until the database is up and running.</p>



<p>We can additionally verify if that&#8217;s the case using <code class="EnlighterJSRAW" data-enlighter-language="raw">docker ps</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">CONTAINER ID IMAGE    COMMAND                CREATED     STATUS           PORTS                  NAMES
1863e6ec964a postgres "docker-entrypoint.s…" 6 hours ago Up About an hour 0.0.0.0:5432->5432/tcp some-postgres</pre>



<p>This one, simple command results in a couple of interesting things happening underneath:</p>



<ul class="wp-block-list">
<li>firstly, it creates a new container named <em>some-postgres</em> and exposes its port 5432 to 5432 of the host machine (localhost in most cases),</li>



<li>secondly, it creates a default Postgres user called <em>postgres</em> and sets its password using the POSTGRES_PASSWORD environment value (of course, we can create another user using the POSTGRES_USER environment variable),</li>



<li>and lastly, it starts in a detached mode thanks to the <code data-enlighter-language="raw" class="EnlighterJSRAW">-d</code> flag.</li>
</ul>


<p>[elementor-template id=&#8221;9007393&#8243;]</p>



<h3 class="wp-block-heading" id="h-2-2-create-and-populate-the-database">2.2 Create And Populate The Database</h3>



<p>As the next step, let&#8217;s connect to the database, and create a schema with two tables:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">create schema if not exists application;

create table if not exists application.company(
  id serial not null primary key,
  name varchar(255) not null,
  address varchar(255) not null
);

create table if not exists application.app_user(
  id serial not null primary key,
  email varchar(255) not null unique,
  name varchar(255) not null,
  age int not null, 
  company_id bigint not null references application.company(id) on delete cascade
);
</pre>



<p>As we can see, the purpose of our application will be users and companies management. Each user will have to be assigned to some company. Moreover, if a company is deleted, then the related user rows will be removed, as well.</p>



<p>Additionally, we can populate tables with the following script:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">insert into application.company(name, address) values
  ('Company 1', 'Address 1'),
  ('Company 2', 'Address 2'),
  ('Company 3', 'Address 3');

insert into application.app_user(email, name, age, company_id) values
  ('email-1@codersee.com', 'John', 23, 1),
  ('email-2@codersee.com', 'Adam', 33, 1),
  ('email-3@codersee.com', 'Maria', 40, 2),
  ('email-4@codersee.com', 'James', 39, 3),
  ('email-5@codersee.com', 'Robert', 41, 3),
  ('email-6@codersee.com', 'Piotr', 28, 3);
</pre>



<h2 class="wp-block-heading" id="h-3-generate-new-project">3. Generate New Project</h2>



<p>With that being done, let&#8217;s navigate to the <a href="https://start.spring.io/" target="_blank" rel="noopener">Spring Initializr</a> page and generate a new project:</p>



<figure class="wp-block-image aligncenter"><img loading="lazy" decoding="async" width="1488" height="807" src="http://blog.codersee.com/wp-content/uploads/2023/03/spring_boot_3_kotlin_coroutines_spring_initializr_page.png" alt="Image is a screenshot from the Spring Initializr page showing necessary configuration to create a Spring Boot 3 Kotlin coroutines project. " class="wp-image-6004389" srcset="https://blog.codersee.com/wp-content/uploads/2023/03/spring_boot_3_kotlin_coroutines_spring_initializr_page.png 1488w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_boot_3_kotlin_coroutines_spring_initializr_page-300x163.png 300w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_boot_3_kotlin_coroutines_spring_initializr_page-1024x555.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_boot_3_kotlin_coroutines_spring_initializr_page-768x417.png 768w" sizes="auto, (max-width: 1488px) 100vw, 1488px" /></figure>



<p>The above configuration is all we need in order to create a fresh Spring Boot 3 project with Kotlin and coroutines. Additionally, in order to connect to the Postgres database, we need two more dependencies: Spring Data R2DBC and PostgreSQL Driver.</p>



<p>With that being done, let&#8217;s hit the <em>Generate </em>button and import the project to our IDE (you can find a video on how to configure <a href="https://youtu.be/npib90rBLE4" target="_blank" rel="noopener">IntelliJ IDEA for Kotlin right here</a>).</p>



<h2 class="wp-block-heading" id="h-4-configure-r2dbc-connection">4. Configure R2DBC Connection</h2>



<p>Nextly, let&#8217;s open up the <code class="EnlighterJSRAW" data-enlighter-language="raw">application.properties</code> file, change its extension to <code class="EnlighterJSRAW" data-enlighter-language="raw">.yaml</code>, and insert the connection config:</p>



<div>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">spring:
  r2dbc:
    url: r2dbc:postgresql://${DB_HOST:localhost}:5432/
    username: ${DB_USERNAME:postgres}
    password: ${DB_PASSWORD:postgres}</pre>
</div>



<p>This configuration instructs Spring to check DB_HOST, DB_USERNAME, and DB_PASSWORD environment variables first. If a particular variable is missing, then we provide the default values<em>&#8211; localhost</em> and <em>postgres.</em></p>



<h2 class="wp-block-heading" id="h-5-create-models">5. Create Models</h2>



<p>Following, let&#8217;s create a new package called <code class="EnlighterJSRAW" data-enlighter-language="raw">model</code> and introduce classes responsible for mapping database tables.</p>



<p>As the first one, let&#8217;s implement the <em>Company</em>:</p>



<div>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@Table("application.company")
data class Company(
    @Id val id: Long? = null,
    val name: String,
    val address: String
)</pre>
</div>



<p>The <em>@Table</em> and <em>@Id</em> annotations are pretty descriptive and they are necessary in order to configure mapping in Spring. Nevertheless, it&#8217;s worth mentioning that if we do not want to generate identifiers manually, then the identifier fields have to be nullable.</p>



<p>Similarly, let&#8217;s create the <em>User</em> data class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Table("application.app_user")
data class User(
    @Id val id: Long? = null,
    val email: String,
    val name: String,
    val age: Int,
    val companyId: Long
)
</pre>



<h2 class="wp-block-heading" id="h-6-crud-operations-using-kotlin-coroutines">6. CRUD operations using Kotlin Coroutines</h2>



<p>Moving forward, let&#8217;s create the <code class="EnlighterJSRAW" data-enlighter-language="raw">repository</code> package.</p>



<p>In our project, we will utilize the <code class="EnlighterJSRAW" data-enlighter-language="raw">CoroutineCrudRepository</code>&#8211; a dedicated Spring Data repository built on Kotlin coroutines. If you&#8217;ve ever been working with Reactor, then <span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">in a nutshell, <em>Mono&lt;T&gt;</em> functions are replaced with suspended functions returning the type <em>T</em>, and instead of creating <em>Fluxes</em>, we will generate <em>Flows</em>. On the other hand, if you have never worked with Reactor</span></span></span><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">, then Flow&lt;T&gt; return type means that a function returns multiple asynchronously computed values suspend function returns only a single value.<br></span></span></span></p>



<p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">Of course, this is a simplification and if you would like to learn the differences between Fluxes and Flows, then let me know in the comments. </span></span></span></p>



<h3 class="wp-block-heading" id="h-6-1-create-userrepository">6.1 Create UserRepository</h3>



<p>To kick things off, let&#8217;s implement the <em>UserRepository</em> interface:</p>



<div>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">interface UserRepository : CoroutineCrudRepository&lt;User, Long&gt; {
    
  fun findByNameContaining(name: String): Flow&lt;User&gt;
    
  fun findByCompanyId(companyId: Long): Flow&lt;User&gt;

  @Query("SELECT * FROM application.app_user WHERE email = :email")
  fun randomNameFindByEmail(email: String): Flow&lt;User&gt;
}

</pre>
</div>



<p>The <code class="EnlighterJSRAW" data-enlighter-language="raw">CoroutineCrudRepository</code> extends the Spring Data <code class="EnlighterJSRAW" data-enlighter-language="raw">Repository</code> and requires us to provide two types: the domain type and the identifier type- a <em>User</em> and a <em>Long</em> in our case. This interface comes with 15 already implemented functions, like <em>save</em>, <em>findAll</em>, <em>delete</em>, etc.- responsible for generic CRUD operations. This way, we can tremendously reduce the amount of boilerplate in our Kotlin codebase.</p>



<p>Moreover, we make use of two, great features of Spring Data (which are not Kotlin, or coroutines specific):</p>



<ul class="wp-block-list">
<li><a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.details" target="_blank" rel="noopener">Query Methods</a>, which in simple terms allow us to define queries <strong>through function names</strong>. Just like above- the <code class="EnlighterJSRAW" data-enlighter-language="raw">findByNameContaining</code> will be translated into <code class="EnlighterJSRAW" data-enlighter-language="raw">where like..</code> query and&nbsp; <code class="EnlighterJSRAW" data-enlighter-language="raw">findByCompanyId</code> will let us search users by company identifier.</li>



<li><strong>@Query</strong>, which lets us execute both JPQL and native SQL queries.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Note: I&#8217;ve named the third method randomNameFindByEmail just to emphasize, that the function name is irrelevant when using the Query, don&#8217;t do that in your codebase 😀</p>
</blockquote>



<h3 class="wp-block-heading" id="h-6-2-add-companyrepository">6.2 Add CompanyRepository</h3>



<p>Nextly, let&#8217;s add the CompanyRepository with only one custom function:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Repository
interface CompanyRepository : CoroutineCrudRepository&lt;Company, Long> {
    fun findByNameContaining(name: String): Flow&lt;Company>
}</pre>



<h2 class="wp-block-heading" id="h-7-create-services">7. Create Services</h2>



<p>With model and repository layer implemented, we can move on and create a <code class="EnlighterJSRAW" data-enlighter-language="raw">service</code> package.</p>



<h3 class="wp-block-heading" id="h-7-1-implement-userservice">7.1 Implement UserService</h3>



<p>Firstly, let&#8217;s add the <code class="EnlighterJSRAW" data-enlighter-language="raw">UserService</code> to our project:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Service
class UserService(
    private val userRepository: UserRepository
) {

    suspend fun saveUser(user: User): User? =
        userRepository.randomNameFindByEmail(user.email)
            .firstOrNull()
            ?.let { throw ResponseStatusException(HttpStatus.BAD_REQUEST, "The specified email is already in use.") }
            ?: userRepository.save(user)

    suspend fun findAllUsers(): Flow&lt;User> =
        userRepository.findAll()

    suspend fun findUserById(id: Long): User? =
        userRepository.findById(id)

    suspend fun deleteUserById(id: Long) {
        val foundUser = userRepository.findById(id)

        if (foundUser == null)
            throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")
        else
            userRepository.deleteById(id)
    }

    suspend fun updateUser(id: Long, requestedUser: User): User {
        val foundUser = userRepository.findById(id)

        return if (foundUser == null)
            throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")
        else
            userRepository.save(
                requestedUser.copy(id = foundUser.id)
            )
    }

    suspend fun findAllUsersByNameLike(name: String): Flow&lt;User> =
        userRepository.findByNameContaining(name)

    suspend fun findUsersByCompanyId(id: Long): Flow&lt;User> =
        userRepository.findByCompanyId(id)
}
</pre>



<p>All the magic starts with the <em>@Service</em> annotation, which is a specialization of a <em>@Component</em>. This way, we simply instruct Spring to create a bean of UserService.</p>



<p>As we can clearly see, our service logic is really straightforward, and thanks to the coroutines we can write code similar to imperative programming.</p>



<p>Lastly, I just wanted to mention the logic responsible for User updates. The <code class="EnlighterJSRAW" data-enlighter-language="raw">save</code> method of the <code class="EnlighterJSRAW" data-enlighter-language="raw">Repository</code> interface works in two ways:</p>



<ul class="wp-block-list">
<li>when the value of a field marked with <em>@Id</em> is set to null, a new entry will be created in the database,</li>



<li>nevertheless, if the id is not null, then the row with the specified will be updated.</li>
</ul>



<h3 class="wp-block-heading" id="h-7-2-create-companyservice">7.2 Create CompanyService</h3>



<p>Following, let&#8217;s implement the <code class="EnlighterJSRAW" data-enlighter-language="raw">CompanyService</code> responsible for companies management:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Component
class CompanyService(
    private val companyRepository: CompanyRepository
) {

    suspend fun saveCompany(company: Company): Company? =
        companyRepository.save(company)

    suspend fun findAllCompanies(): Flow&lt;Company> =
        companyRepository.findAll()

    suspend fun findCompanyById(id: Long): Company? =
        companyRepository.findById(id)

    suspend fun deleteCompanyById(id: Long) {
        val foundCompany = companyRepository.findById(id)

        if (foundCompany == null)
            throw ResponseStatusException(HttpStatus.NOT_FOUND, "Company with id $id was not found.")
        else
            companyRepository.deleteById(id)
    }

    suspend fun findAllCompaniesByNameLike(name: String): Flow&lt;Company> =
        companyRepository.findByNameContaining(name)

    suspend fun updateCompany(id: Long, requestedCompany: Company): Company {
        val foundCompany = companyRepository.findById(id)

        return if (foundCompany == null)
            throw ResponseStatusException(HttpStatus.NOT_FOUND, "Company with id $id was not found.")
        else
            companyRepository.save(
                requestedCompany.copy(id = foundCompany.id)
            )
    }

}
</pre>



<h2 class="wp-block-heading" id="h-8-implement-controllers">8. Implement Controllers</h2>



<p>And the last thing we need to implement in our Spring Kotlin Coroutines project are&#8230; REST endpoints (and a couple of DTOs 😉 ).</p>



<h3 class="wp-block-heading" id="h-8-1-create-userresponse-and-userrequest">8.1. Create UserResponse and UserRequest</h3>



<p>When working in real-life scenarios we can use different approaches, when it comes to serialization and deserialization of data (or in simple terms- JSON &lt;-&gt; Kotlin objects conversions). In some cases dealing with model classes might be sufficient, but introducing DTOs will usually be a better approach. In our examples, we will introduce separate request and response classes, which in my opinion let us maintain our codebase much easier.</p>



<p>To do so, let&#8217;s add two data classes to our codebase- the <code class="EnlighterJSRAW" data-enlighter-language="raw">UserRequest</code> and <code class="EnlighterJSRAW" data-enlighter-language="raw">UserResponse</code> (inside the <code class="EnlighterJSRAW" data-enlighter-language="raw">dto</code> package):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class UserRequest(
    val email: String,
    val name: String,
    val age: Int,
    @JsonProperty("company_id") val companyId: Long
)

data class UserResponse(
    val id: Long,
    val email: String,
    val name: String,
    val age: Int
)</pre>



<p>Request classes will be used to translate JSON payload into Kotlin objects, whereas the response ones will do the opposite.</p>



<p>Additionally, we make use of the <code class="EnlighterJSRAW" data-enlighter-language="raw">@JsonProperty</code> annotation, so that our JSON files will use the <strong>snake case</strong>.</p>



<h3 class="wp-block-heading" id="h-8-2-implement-usercontroller">8.2. Implement UserController</h3>



<p>With that prepared, we have nothing else to do than create a <code class="EnlighterJSRAW" data-enlighter-language="raw">controller</code> package and implement the UserController:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestController
@RequestMapping("/api/users")
class UserController(
    private val userService: UserService
) {

    @PostMapping
    suspend fun createUser(@RequestBody userRequest: UserRequest): UserResponse =
        userService.saveUser(
            user = userRequest.toModel()
        )
            ?.toResponse()
            ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error during user creation.")

    @GetMapping
    suspend fun findUsers(
        @RequestParam("name", required = false) name: String?
    ): Flow&lt;UserResponse> {
        val users = name?.let { userService.findAllUsersByNameLike(name) }
            ?: userService.findAllUsers()

        return users.map(User::toResponse)
    }

    @GetMapping("/{id}")
    suspend fun findUserById(
        @PathVariable id: Long
    ): UserResponse =
        userService.findUserById(id)
            ?.let(User::toResponse)
            ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "User with id $id was not found.")

    @DeleteMapping("/{id}")
    suspend fun deleteUserById(
        @PathVariable id: Long
    ) {
        userService.deleteUserById(id)
    }

    @PutMapping("/{id}")
    suspend fun updateUser(
        @PathVariable id: Long,
        @RequestBody userRequest: UserRequest
    ): UserResponse =
        userService.updateUser(
            id = id,
            requestedUser = userRequest.toModel()
        )
            .toResponse()
}

private fun UserRequest.toModel(): User =
    User(
        email = this.email,
        name = this.name,
        age = this.age,
        companyId = this.companyId
    )

fun User.toResponse(): UserResponse =
    UserResponse(
        id = this.id!!,
        email = this.email,
        name = this.name,
        age = this.age
    )
</pre>



<p>I know, the class itself might be a little big, but let&#8217;s break it down into parts first. We have a couple of annotations here, so why don&#8217;t we start with them?</p>



<p>The <em>@RestController</em> is nothing else, then a combination of a <em>@Controller</em>&#8211; informing Spring that our class is a web controller and a <em>@ResponseBody-</em> which indicates that the things our functions return should be bound to the web response body (simply- returned to the API user).</p>



<p>The <em>@RequestMapping</em> allows us to specify the path, to which our class will respond. So, each time we will hit the <code class="EnlighterJSRAW" data-enlighter-language="raw">localhost:8080/api/users</code>, Spring will search for a handler function inside this class.</p>



<p>On the other hand, the <em>@PostMapping</em>, <em>@GetMapping</em>, etc. simply indicate for which HTTP methods a particular function should be invoked (and also can take the additional path segments).</p>



<p>Lastly, the <em>@RequestParam</em>, <em>@PathVariable</em>, and <em>@RequestBody</em> are used to map request parameters, segment paths, and body payload to Kotlin class instances.</p>



<p>The rest of the code is responsible for invoking our service methods and throwing meaningful errors when something is wrong (with a help of extension functions used to map between models and responses).</p>



<h3 class="wp-block-heading" id="h-8-3-implement-companyresponse-and-companyrequest">8.3. Implement CompanyResponse and CompanyRequest</h3>



<p>Similarly, let&#8217;s add response and request classes for Company resources:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class CompanyRequest(
    val name: String,
    val address: String
)

data class CompanyResponse(
    val id: Long,
    val name: String,
    val address: String,
    val users: List&lt;UserResponse>
)
</pre>



<h3 class="wp-block-heading" id="h-8-4-add-companycontroller">8.4. Add CompanyController</h3>



<p>And this time, let&#8217;s add the <code class="EnlighterJSRAW" data-enlighter-language="raw">CompanyController</code> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestController
@RequestMapping("/api/companies")
class CompanyController(
    private val companyService: CompanyService,
    private val userService: UserService
) {

    @PostMapping
    suspend fun createCompany(@RequestBody companyRequest: CompanyRequest): CompanyResponse =
        companyService.saveCompany(
            company = companyRequest.toModel()
        )
            ?.toResponse()
            ?: throw ResponseStatusException(
                HttpStatus.INTERNAL_SERVER_ERROR,
                "Unexpected error during company creation."
            )

    @GetMapping
    suspend fun findCompany(
        @RequestParam("name", required = false) name: String?
    ): Flow&lt;CompanyResponse> {
        val companies = name?.let { companyService.findAllCompaniesByNameLike(name) }
            ?: companyService.findAllCompanies()

        return companies
            .map { company ->
                company.toResponse(
                    users = findCompanyUsers(company)
                )
            }
    }


    @GetMapping("/{id}")
    suspend fun findCompanyById(
        @PathVariable id: Long
    ): CompanyResponse =
        companyService.findCompanyById(id)
            ?.let { company ->
                company.toResponse(
                    users = findCompanyUsers(company)
                )
            }
            ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Company with id $id was not found.")

    @DeleteMapping("/{id}")
    suspend fun deleteCompanyById(
        @PathVariable id: Long
    ) {
        companyService.deleteCompanyById(id)
    }

    @PutMapping("/{id}")
    suspend fun updateCompany(
        @PathVariable id: Long,
        @RequestBody companyRequest: CompanyRequest
    ): CompanyResponse =
        companyService.updateCompany(
            id = id,
            requestedCompany = companyRequest.toModel()
        )
            .let { company ->
                company.toResponse(
                    users = findCompanyUsers(company)
                )
            }

    private suspend fun findCompanyUsers(company: Company) =
        userService.findUsersByCompanyId(company.id!!)
            .toList()
}


private fun CompanyRequest.toModel(): Company =
    Company(
        name = this.name,
        address = this.address
    )

private fun Company.toResponse(users: List&lt;User> = emptyList()): CompanyResponse =
    CompanyResponse(
        id = this.id!!,
        name = this.name,
        address = this.address,
        users = users.map(User::toResponse)
    )

</pre>



<p>And although this controller class looks similar, I wanted to emphasize two things:</p>



<ul class="wp-block-list">
<li>Firstly, thanks to coroutines we don&#8217;t have to do any sophisticated mapping, zipping, etc. (known from Reactor) in order to fetch users for each company,</li>



<li>and secondly- in order to edit Flow elements we use the map intermediate operator, which works just like a map when dealing with collections.</li>
</ul>



<h3 class="wp-block-heading" id="h-8-5-create-idnametyperesponse">8.5 Create IdNameTypeResponse</h3>



<p>As the last thing, I wanted to show you how easily we can merge two Flows. And to do so, let&#8217;s introduce a new search endpoint, which will be used to return both users and companies by their names.</p>



<p>So firstly, let&#8217;s add the <code class="EnlighterJSRAW" data-enlighter-language="raw">IdNameTypeResponse</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class IdNameTypeResponse(
    val id: Long,
    val name: String,
    val type: ResultType
)

enum class ResultType {
    USER, COMPANY
}</pre>



<h3 class="wp-block-heading" id="h-8-6-add-searchcontroller">8.6 Add SearchController</h3>



<p>Moving forward, let&#8217;s implement the <code class="EnlighterJSRAW" data-enlighter-language="raw">SearchController</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RestController
@RequestMapping("/api/search")
class SearchController(
  private val userService: UserService,
  private val companyService: CompanyService
) {

  @GetMapping
  suspend fun searchByNames(
    @RequestParam(name = "query") query: String
  ): Flow&lt;IdNameTypeResponse> {
    val usersFlow = userService.findAllUsersByNameLike(name = query)
      .map(User::toIdNameTypeResponse)
    val companiesFlow = companyService.findAllCompaniesByNameLike(name = query)
      .map(Company::toIdNameTypeResponse)

    return merge(usersFlow, companiesFlow)
  }
}

  private fun User.toIdNameTypeResponse(): IdNameTypeResponse =
    IdNameTypeResponse(
      id = this.id!!,
      name = this.name,
      type = ResultType.USER
    )

  private fun Company.toIdNameTypeResponse(): IdNameTypeResponse =
    IdNameTypeResponse(
      id = this.id!!,
      name = this.name,
      type = ResultType.COMPANY
    )</pre>



<p>As we can see, in order to combine together both user and company results we can use the <strong>merge</strong> function. This way, our flows are merged concurrently (and without preserving the order), without limit on the number of simultaneously collected flows.</p>



<h2 class="wp-block-heading" id="h-9-testing">9. Testing</h2>



<p>At this point, we have everything we need to start testing, so let it be your homework. Going through all of the handler methods and preparing appropriate requests will be a great opportunity to recap everything we learned today 🙂</p>



<p>As a bonus- right here you can find a ready-to-go <a href="https://drive.google.com/file/d/1xq3njZk2oGwHQGZkTFf05VwHr1pdsJJE/view?usp=sharing" target="_blank" rel="noopener">Postman collection</a>, which you can import to your computer.</p>



<h2 class="wp-block-heading" id="h-10-rest-api-with-spring-kotlin-coroutines-and-kotlin-flows-summary">10. REST API with Spring, Kotlin, coroutines, and Kotlin Flows Summary</h2>



<p>And that&#8217;s all for this hands-on tutorial, in which we&#8217;ve learned together how to create a REST API using Spring, Kotlin, coroutines, and Kotlin Flows. As always, you can find the whole project in this <a href="https://github.com/codersee-blog/spring-boot-3-kotlin-coroutines" target="_blank" rel="noopener">GitHub repository</a>.</p>



<p>If you&#8217;re interested in learning more about the reactive approach, then check out my other materials in the <a href="https://blog.codersee.com/tag/webflux/">Spring Webflux</a> tag.</p>



<p>I hope you enjoyed this article and will be forever thankful for your feedback in the comments section 🙂</p>
<p>The post <a href="https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/">Reactive REST API With Spring, Kotlin, and Coroutines</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/reactive-rest-api-with-spring-kotlin-and-coroutines/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-02-27 03:25:23 by W3 Total Cache
-->