<?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>Peter Lantukh, Author at Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/author/peterlantukh/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Thu, 15 Feb 2024 05:00:00 +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>Peter Lantukh, Author at Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<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 fetchpriority="high" 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="(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 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="(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>How To Create a Ktor Client To Connect To OpenWeatherMap API</title>
		<link>https://blog.codersee.com/how-to-create-a-ktor-client-to-connect-to-openweathermap-api/</link>
					<comments>https://blog.codersee.com/how-to-create-a-ktor-client-to-connect-to-openweathermap-api/#respond</comments>
		
		<dc:creator><![CDATA[Peter Lantukh]]></dc:creator>
		<pubDate>Wed, 17 Jan 2024 05:15:00 +0000</pubDate>
				<category><![CDATA[Ktor]]></category>
		<category><![CDATA[Ktor Client]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9508613</guid>

					<description><![CDATA[<p>This article provides all the necessary information you need to know about setting up a Ktor client with OpenWeatherMap API.</p>
<p>The post <a href="https://blog.codersee.com/how-to-create-a-ktor-client-to-connect-to-openweathermap-api/">How To Create a Ktor Client To Connect To OpenWeatherMap API</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This comprehensive guide is about setting up a Ktor client that effortlessly retrieves data from OpenWeatherMap API. I&#8217;ll tackle client configuration, API calls, models configuration, and <strong>error handling</strong>, leaving you with a weather-fetching client ready to be used on any platform.</p>



<p><strong>Ktor</strong> is a flexible library that provides the ability to create a non-blocking <strong>HTTP client</strong>, which enables you to perform requests and handle responses. Its functionality could be enhanced with plugins, such as logging, serialization, authentication, and so on. Its core benefit is that it&#8217;s a lightweight framework that can be used on different platforms such as <strong>Android, JVM, or Native</strong>!</p>



<h2 class="wp-block-heading" id="h-general-overview">General Overview</h2>



<p>Let&#8217;s discuss some basic information for everyone to be on the same page.  </p>



<p>Today, we are going to write HTTP requests and receive responses. There are different types of requests but OpenWeatherMap for the most part utilizes <strong>GET requests</strong> with various parameters.</p>



<p>OpenWeatherMap API, as you can tell by its name, is an API for retrieving weather-related data. It provides various types of data but we&#8217;re going to use only 3 of them:</p>



<ul class="wp-block-list">
<li>Current Weather, </li>



<li>3-hours Forecast, </li>



<li>and Air Pollution API.</li>
</ul>



<p>To start using OpenWeatherMap <a href="https://home.openweathermap.org/subscriptions/unauth_subscribe/onecall_30/base" target="_blank" rel="noreferrer noopener nofollow">you need to register</a> and get your special API key. It has lots of free options and for our sake, we don&#8217;t need to pay at all. </p>



<p>But be aware of the limitations of the call: <strong>1,000 API calls per day for free</strong>!</p>



<h2 class="wp-block-heading" id="h-gradle-dependencies">Gradle Dependencies</h2>



<p>For this project, we&#8217;re going to use basic <strong>Ktor&#8217;s client, serialization, engines, and logging</strong>. </p>



<p>Your <strong>build.gradle.kts</strong> file would look like this:</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 ktor_version: String by project
val kotlin_version: String by project
val logback_version: String by project

plugins {
    kotlin("jvm") version "1.9.21"
    id("io.ktor.plugin") version "2.3.6"
    id("org.jetbrains.kotlin.plugin.serialization") version "1.9.21"
    application
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.ktor:ktor-client-core-jvm")
    implementation("io.ktor:ktor-client-cio-jvm")

    implementation("io.ktor:ktor-serialization-kotlinx-json-jvm")
    implementation("io.ktor:ktor-client-content-negotiation-jvm")

    implementation("ch.qos.logback:logback-classic:$logback_version")
    implementation("io.ktor:ktor-client-logging:$ktor_version")
    implementation("io.ktor:ktor-client-apache5:$ktor_version")

    testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}</pre>



<h2 class="wp-block-heading" id="h-creating-models">Creating Models</h2>



<p>The first step of creating a Ktor client is actually revealing what we&#8217;re gonna handle. Basically, we need <strong>2</strong> types of models: <strong>request and response</strong>. All necessary information is located on the corresponding page of the documentation. The documentation is pretty neat and, generally, it&#8217;s a good practice to check it out during the coding!</p>



<p>To optimize the process we could spot similar parameters appearing in the Current Weather and Weather Forecast. Such as Mode and Units. </p>



<p>So we can create separate classes and use the latter like this:</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 ResponseUnits {
    STANDARD,
    METRIC,
    IMPERIAL
}

enum class ResponseMode {
    XML
}
</pre>



<p>Now let&#8217;s create the request themselves. </p>



<p>As there are some optional parameters present we&#8217;re going to make them nullable with default value null so that we could use them or not with ease. </p>



<p>Here are the models for requests:</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 CurrentWeatherRequest(
    val latitude: Double,
    val longitude: Double,
    val mode: ResponseMode? = null,
    val units: ResponseUnits? = null,
    val language: String? = null
)

data class WeatherForecastRequest(
    val latitude: Double,
    val longitude: Double,
    val mode: ResponseMode? = null,
    val units: ResponseUnits? = null,
    val language: String? = null,
    val count: Int? = null
)

data class AirPollutionRequest(
    val latitude: Double,
    val longitude: Double
)</pre>



<p>Consequently, we desperately need models to put our data to: <strong>the response models</strong>. </p>



<p>It&#8217;s the most routine process because there are some huge responses and by &#8216;huge&#8217; I mean lots of parameters. Let&#8217;s dive deep into one model and the rest would be easy to create. </p>



<p>Here&#8217;s what our <strong>JSON</strong> of current weather data looks like (there is also a text representation of this JSON with more information about parameters):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "coord": {
    "lon": 10.99,
    "lat": 44.34
  },
  "weather": [
    {
      "id": 501,
      "main": "Rain",
      "description": "moderate rain",
      "icon": "10d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 298.48,
    "feels_like": 298.74,
    "temp_min": 297.56,
    "temp_max": 300.05,
    "pressure": 1015,
    "humidity": 64,
    "sea_level": 1015,
    "grnd_level": 933
  },
  "visibility": 10000,
  "wind": {
    "speed": 0.62,
    "deg": 349,
    "gust": 1.18
  },
  "rain": {
    "1h": 3.16
  },
  "clouds": {
    "all": 100
  },
  "dt": 1661870592,
  "sys": {
    "type": 2,
    "id": 2075663,
    "country": "IT",
    "sunrise": 1661834187,
    "sunset": 1661882248
  },
  "timezone": 7200,
  "id": 3163858,
  "name": "Zocca",
  "cod": 200
}</pre>



<p>Now we have to face some difficulties. Not only do we have to parse it but also there are some <strong>optional parameters</strong>. </p>



<p>To solve the first issue we mark our classes with <strong>@Serializable</strong> and <strong>@SerialName</strong> annotations. I highly recommend using @SerialName because it provides <strong>enhanced readability</strong> and usability especially when handling such long classes. </p>



<p>To solve the second problem I recommend you to read my <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/" target="_blank" rel="noreferrer noopener">detailed guide</a> that covers all essential information about Serialization. Basically, if we want to parse all of the data, we make <strong>optional fields</strong> with <strong>@EncodeDefault</strong> and make it <strong>nullable with the default value as null</strong>. This makes sure that if there was no such a field we would get a null, without any exceptions. </p>



<p>Now let&#8217;s look at classes for our Ktor client:</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="">@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class CurrentWeather(
    @SerialName("coord") val coordinates: Coordinates,
    @SerialName("weather") val weather: List&lt;Weather&gt;,
    @SerialName("base") val base: String,
    @SerialName("main") val main: Main,
    @SerialName("visibility") val visibility: Int,
    @SerialName("wind") val wind: Wind,
    @SerialName("rain")
    @EncodeDefault
    val rain: Rain? = null,
    @SerialName("snow")
    @EncodeDefault
    val snow: Snow? = null,
    @SerialName("clouds") val clouds: Clouds,
    @SerialName("dt") val dateTime: Long,
    @SerialName("sys") val systemData: SystemData,
    @SerialName("timezone") val timezone: Int,
    @SerialName("id") val cityId: Int,
    @SerialName("name") val cityName: String,
    @SerialName("cod") val code: Int
) {

    //other classes here

    @Serializable
    data class Wind(
        @SerialName("speed") val speed: Double,
        @SerialName("deg") val direction: Int,
        @SerialName("gust") val gust: Double
    )

    @Serializable
    data class Rain(
        @SerialName("1h")
        @EncodeDefault
        val oneHour: Double? = null,
        @SerialName("3h")
        @EncodeDefault
        val threeHours: Double? = null
    )

	//other classes here
}</pre>



<p>The rest of the responses are quite similar so you could check them out in the repository that comes with this article. </p>



<p>Quick remark, I&#8217;ve made classes such as Coordinates, Weather, etc. as inner classes since there are the same classes for other responses but with different structures. </p>



<p>This approach helps not to mix them up.</p>



<h2 class="wp-block-heading" id="h-creating-the-ktor-client-itself">Creating The Ktor Client Itself</h2>



<p>We are gonna be using <strong>Ktor&#8217;s HttpClient</strong> with some adjustments and extended configuration. </p>



<p>Let&#8217;s check it out:</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="">private val client = HttpClient(Apache5) {
        install(ContentNegotiation) {
            json(Json {
                isLenient = false
            })
        }
        install(Logging)
        defaultRequest {
            url {
                protocol = URLProtocol.HTTPS
                host = "api.openweathermap.org/data/2.5"
            }
        }
    }</pre>



<p>First of all, we have the <strong>Apache5</strong> engine rather than <strong>CIO</strong>, for example, because it&#8217;s suitable for <strong>HTTP/2</strong> while CIO is not. </p>



<p>Next, we have 2 plugins: the <strong>ContentNegotiation</strong> for the <strong>JSON</strong> parsing and the <strong>Logging</strong> for detailed logs. </p>



<p>Also, as all of our requests to OpenWeatherMap have similar endpoints, we can use <strong>defaultRequest</strong> to shorten our request&#8217;s links. The whole defaultRequest translates to https://api.openweathermap.org/data/2.5/. We&#8217;ll combine this with the request&#8217;s specific <strong>parameters</strong>. </p>



<p>Now let&#8217;s talk about them.</p>



<h2 class="wp-block-heading" id="h-creating-routes">Creating Routes</h2>



<p>As all of our routes would share similar logic let&#8217;s look closely at only one of them for the Current Weather:</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 getCurrentWeather(currentWeatherRequest: CurrentWeatherRequest): CurrentWeather? {
        return try {
            val response: HttpResponse = client
                .get("/weather") {
                    url {
                        parameters.append("lat", currentWeatherRequest.latitude.toString())
                        parameters.append("lon", currentWeatherRequest.longitude.toString())
                        parameters.append("appid", APP_ID)
                        if (currentWeatherRequest.mode != null) parameters.append(
                            "mode",
                            currentWeatherRequest.mode.name()
                        )
                        if (currentWeatherRequest.units != null) parameters.append(
                            "units",
                            currentWeatherRequest.units.name()
                        )
                        if (currentWeatherRequest.language != null) parameters.append(
                            "lang",
                            currentWeatherRequest.language
                        )
                    }
                }

            if (response.status == HttpStatusCode.OK) {
                response.body&lt;CurrentWeather&gt;()
            } else {
                println("Failed to retrieve current weather. Status: ${response.status}")
                null
            }
        } catch (e: Exception) {
            println("Error retrieving current weather: ${e.message}")
            null
        }
    }</pre>



<p>Here we create <strong>GET HttpResponse</strong> with the path &#8220;/weather&#8221; and then we specify <strong>additional parameters</strong>, note that it&#8217;ll automatically use the correct notation(? and other). </p>



<p>In the URL block, we list all of our parameters using <strong>parameters.append()</strong> function that takes the name and the value. There is no need to include <strong>optional parameters</strong> that are not specified, so we simply check whether they&#8217;re null or not.</p>



<p>Our Ktor client also implements <strong>error handling</strong>. </p>



<p>For the errors with the request itself, such as connection problems, any issues from the server, etc. we&#8217;ll get the &#8220;Error retrieving current weather:&#8221; message and null result. </p>



<p>And if your request is successful but has some undesired response, in our case everything except 200 OK, we&#8217;ll get &#8220;Failed to retrieve current weather. Status:&#8221; and null result as well.</p>



<h2 class="wp-block-heading" id="h-ktor-client-in-action">Ktor Client In Action</h2>



<p>To use the client you could simply call our object with the corresponding method like this:</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="">WeatherClient.getCurrentWeather(
        CurrentWeatherRequest(
            latitude = 44.34,
            longitude = 10.99,
            units = ResponseUnits.IMPERIAL,
            language = "pl"
        )
    )
	
	WeatherClient.getWeatherForecast(
        WeatherForecastRequest(
            latitude = 44.34,
            longitude = 10.99,
            units = ResponseUnits.IMPERIAL,
            language = "pl"
        )
    )
	
	WeatherClient.getAirPollution(
        AirPollutionRequest(
            latitude = 50.0,
            longitude = 50.0
        )
    )</pre>



<p>This could be used on every platform but as I&#8217;ve mentioned before make sure you&#8217;re using the correct engine!</p>



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



<p>And that’s all for this article about the <strong>OpenWeatherMap API Ktor client</strong>.</p>



<p>If you would like to download the full source code, then you can find it in this <a href="https://github.com/codersee-blog/kotlin-ktor-client-weather">GitHub repository</a>.</p>



<p>Lastly, thank you for being here, and happy to hear your feedback in the comments section below!</p>
<p>The post <a href="https://blog.codersee.com/how-to-create-a-ktor-client-to-connect-to-openweathermap-api/">How To Create a Ktor Client To Connect To OpenWeatherMap API</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/how-to-create-a-ktor-client-to-connect-to-openweathermap-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How To Use kotlinx.serialization with Ktor and Kotlin?</title>
		<link>https://blog.codersee.com/how-to-use-kotlinx-serialization-with-ktor-and-kotlin/</link>
					<comments>https://blog.codersee.com/how-to-use-kotlinx-serialization-with-ktor-and-kotlin/#respond</comments>
		
		<dc:creator><![CDATA[Peter Lantukh]]></dc:creator>
		<pubDate>Tue, 02 Jan 2024 06:00:00 +0000</pubDate>
				<category><![CDATA[Ktor]]></category>
		<category><![CDATA[kotlinx.serialization]]></category>
		<category><![CDATA[Ktor Client]]></category>
		<category><![CDATA[Ktor Server]]></category>
		<category><![CDATA[Serialization]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9008447</guid>

					<description><![CDATA[<p>This article is all you need to know about how to set up kotlinx.serialization library in Ktor Server, Client, and WebSockets. </p>
<p>The post <a href="https://blog.codersee.com/how-to-use-kotlinx-serialization-with-ktor-and-kotlin/">How To Use kotlinx.serialization with Ktor and Kotlin?</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you would like to learn how to use the <strong>kotlinx.serialization library with Ktor</strong> and Kotlin, then you just came to the right place! In this article, I will show you how to configure it to work with: </p>



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



<li>Ktor Client </li>



<li>WebSockets in Ktor</li>
</ul>



<p>Before we start, I just wanted to note that we are going to use a modified project from the lesson about <a href="https://blog.codersee.com/rest-api-ktor-ktorm-postgresql/" target="_blank" rel="noreferrer noopener">Ktor with Ktorm and PostgreSQL</a>. So if you don&#8217;t know how to set up and use a Ktor server with PostgreSQL you should definitely check it up, because I will skip the basics. Additionally, if you&#8217;d like to explore kotlinx.serialization in details, then check out my <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/" target="_blank" rel="noreferrer noopener">detailed guide</a>.</p>



<p>Lastly, please note that there is a <strong>GitHub repository</strong> for all of this in the end of this lesson!</p>



<h2 class="wp-block-heading" id="h-setup">Setup</h2>



<p>A few quick words about setting up. Note that for the main thing we are going to use, such as <strong>ContentNegotiation</strong>, Ktor has <strong>different implementations for Client and Server</strong>. </p>



<p>Do not mess them up, it causes a lot of trouble and a lot of Stack Overflow questions 🙂</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="">//server
implementation("io.ktor:ktor-server-content-negotiation-jvm")
//client
implementation("io.ktor:ktor-client-content-negotiation-jvm")</pre>



<h2 class="wp-block-heading" id="h-kotlinx-serialization-with-ktor-server">kotlinx.serialization With Ktor Server</h2>



<p>Now, let&#8217;s start with the kotlinx.serialization for the Ktor server part. </p>



<p>I am going to use <strong>Postman</strong> for making HTTP<strong> requests</strong> and testing the server. You can use any tool for this purpose even the client we will write about in the next part 🙂</p>



<p>First of all, let&#8217;s check our classes for the User from previous parts:</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="">interface User : Entity&lt;User> {  
  companion object : Entity.Factory&lt;User>()  
  
  val userId: Long?  
  var userName: String  
}</pre>



<p>&nbsp;Now we are going to need classes for our responses:&nbsp;</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="">@Serializable  
data class UserResponse(  
  val userId: Long,  
  val userName: String  
)  
  
@Serializable  
data class UserRequest(  
  val userName: String  
)

@Serializable  
data class UserErrorResponse(val message: String)</pre>



<p>Basically, the central part of all serialization here is <strong>ContentNegotiation</strong> which could be installed for our server(not the client). </p>



<p>As we are using it for Json serialization, we should specify it as <strong>json()</strong> like this:</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.configureSerialization() {  
  install(ContentNegotiation) {  
    json(Json {  
      prettyPrint = true  
      isLenient = true  
    })  
  }  
}</pre>



<p>And here&#8217;s our loved <strong>Json</strong> object! Now we can do all kinds of trickery that we know and learned before.</p>



<p>For the code above, I&#8217;ve used a simple style specification, but you can use it as you like. As an example, we can add a custom or polymorphic serializer:</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="">private val contextualSerializerModule = SerializersModule {
  contextual&lt;Date>(DateAsStringSerializer)
}

private val polymorphicSerializationModule = SerializersModule {
  polymorphic(User::class) {
    subclass(Admin::class, Admin.serializer())
    subclass(Guest::class, Guest.serializer())
  }
}

object DateAsStringSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
    "Date", 
    PrimitiveKind.STRING,
  )

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}
</pre>



<p>And our server is going to look like this:&nbsp;</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.configureSerialization() {
  install(ContentNegotiation) {
    json(Json {
      prettyPrint = true
      isLenient = true
      serializersModule = contextualSerializerModule
      serializersModule = polymorphicSerializationModule
    })
  }
}</pre>



<p>We can remove this for now, we&#8217;ll use actual polymorphic serialization in the Web Sockets section.</p>



<p>Now, what about routes? Let&#8217;s check out a simple <strong>POST</strong> request:</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 Route.createUser(userService: UserService) {
  post {

    val request = call.receive&lt;UserRequest>()

    val success = userService.createUser(userRequest = request)

    if (success)
      call.respond(HttpStatusCode.Created)
    else
      call.respond(HttpStatusCode.BadRequest, UserErrorResponse("Cannot create user"))
  }
}</pre>



<p>As we can see, we don&#8217;t serialize/deserialize anything manually. </p>



<p>The whole process happens due to this line:</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 request = call.receive&lt;UserRequest>()</pre>



<p>We can witness that our request deserializes into the UserRequest as such is marked with <strong>@Serializable</strong> annotation. </p>



<p>The same happens here:</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 Route.updateUserByIdRoute(userService: UserService) {
  patch("/{userId}") {
    val userId: Long = call.parameters["userId"]?.toLongOrNull()
      ?: return@patch call.respond(
          HttpStatusCode.BadRequest, 
          UserErrorResponse("Invalid id")
        )

    val request = call.receive&lt;UserRequest>()
    val success = userService.updateUserById(userId, request)

    if (success)
      call.respond(HttpStatusCode.NoContent)
    else
      call.respond(
        HttpStatusCode.BadRequest,
        UserErrorResponse("Cannot update user with id [$userId]"),
      )
  }
}</pre>



<p>Our request is deserialized and we can update a user. </p>



<p>Now let&#8217;s test it and get our 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="">private fun User?.toUserResponse(): UserResponse? =  
    this?.let { UserResponse(it.userId!!, it.userName) }

fun Route.getAllUsersRoute(userService: UserService) {  
    get {  
        val users = userService.findAllUsers()  
            .map(User::toUserResponse)  
  
        call.respond(message = users)  
    }  
}</pre>



<p>As I said before, I’m going to use Postman. </p>



<p>So how about checking our server:</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="432" height="108" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_4.png" alt="Image shows a GET request URL in Postman. " class="wp-image-9008448" style="aspect-ratio:4;width:432px;height:auto" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_4.png 432w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_4-300x75.png 300w" sizes="(max-width: 432px) 100vw, 432px" /></figure>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="474" height="280" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_6.png" alt="Image shows a response from the GET request serialized with kotlinx serialization in our Ktor server" class="wp-image-9008449" style="aspect-ratio:1.6928571428571428;width:474px;height:auto" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_6.png 474w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_6-300x177.png 300w" sizes="auto, (max-width: 474px) 100vw, 474px" /></figure>



<p>Post:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="391" height="112" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_5-1.png" alt="Image shows the URL for POST request in Postman" class="wp-image-9008451" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_5-1.png 391w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_5-1-300x86.png 300w" sizes="auto, (max-width: 391px) 100vw, 391px" /></figure>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="990" height="150" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_2.png" alt="Screenshot presents the content type header set to application/json" class="wp-image-9008452" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_2.png 990w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_2-300x45.png 300w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_2-768x116.png 768w" sizes="auto, (max-width: 990px) 100vw, 990px" /></figure>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="388" height="124" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_3.png" alt="Screenshot shows the response we get from the POST endpoint in our Ktor server serialized using the kotlinx serialization library" class="wp-image-9008453" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_3.png 388w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_3-300x96.png 300w" sizes="auto, (max-width: 388px) 100vw, 388px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="181" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_1-1024x181.png" alt="Image presents 201 Created response from the POST endpoint" class="wp-image-9008454" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_1-1024x181.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_1-300x53.png 300w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_1-768x136.png 768w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_1.png 1501w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Delete:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="349" height="102" src="http://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_7.png" alt="Image shows the url path for the DELETE endpoint." class="wp-image-9008455" srcset="https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_7.png 349w, https://blog.codersee.com/wp-content/uploads/2023/12/ktor_serialization_7-300x88.png 300w" sizes="auto, (max-width: 349px) 100vw, 349px" /></figure>



<h2 class="wp-block-heading" id="h-kotlinx-serialization-with-ktor-client">kotlinx.serialization With Ktor Client</h2>



<p>Now the kotlinx.serialization for the Ktor client. Here&#8217;s the same thing, but make sure you don&#8217;t miss anything and use <strong>ContentNegotiation FOR CLIENT</strong>. </p>



<p>Check the import:</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="">import io.ktor.client.plugins.contentnegotiation.*</pre>



<p>We can install it just like before:</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="">private val client = HttpClient(CIO) {
  install(ContentNegotiation) {
    json(Json {
      prettyPrint = true
      isLenient = true
    })
  }
  defaultRequest {
    url {
      host = "0.0.0.0"
      path("/")
      port = 8080
    }
  }}
</pre>



<p>All things apply here as well, so let&#8217;s check how to use it for our requests. There are lots of possible situations, we are going to cover basic data retrieving and how to place something inside a <strong>body</strong> of a request.</p>



<p>We want to get all of the users, what should we do? We can use something like this:</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 getAllUsers(): List&lt;UserResponse> {
  return try {
    val response: HttpResponse = client.get("/users")

    if (response.status == HttpStatusCode.OK) {
      response.body&lt;List&lt;UserResponse>>()
    } else {
      println("Failed to retrieve users. Status: ${response.status}")
      emptyList()
    }
  } catch (e: Exception) {
    println("Error retrieving users: ${e.message}")
    emptyList()
  }
}</pre>



<p>The main part here as well is this:</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="">response.body&lt;List&lt;UserResponse>>()</pre>



<p>The UserResponse class can be serialized, and we don&#8217;t need to do anything at all. All hail the <strong>ContentNegotiation</strong> 🙂</p>



<p>How about we create some user? We can do it as well:</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(user: UserRequest) {
  try {
    val response: HttpResponse = client.post("/users") {
      contentType(ContentType.Application.Json)
      setBody(user)
    }

    if (response.status == HttpStatusCode.Created) {
      println("User created successfully")
    } else {
      println("Failed to create user. Status: ${response.status}")
    }
  } catch (e: Exception) {
    println("Error creating user: ${e.message}")
  }
}</pre>



<p>This time, we specify the content type for our body, such as <strong>ContentType.Application.Json</strong> and just set our user in here. All happens as it is a miracle.</p>



<p>Now let’s test it. I’m going to use this simply to check each method:</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="">runBlocking {

  val allUsersOld = UserRequests.getAllUsers()
  println("All Users: $allUsersOld")

  val newUser = UserRequest(
    userName = "Mark"
  )

  UserRequests.createUser(newUser)

  val allUsersNew = UserRequests.getAllUsers()
  println("All Users: $allUsersNew")

  val userIdToRetrieve = 2L
  val retrievedUser = UserRequests.getUserById(userIdToRetrieve)
  println("User with ID $userIdToRetrieve: $retrievedUser")

  val userIdToUpdate = 2L
  val updatedUser = UserRequest(
    userName = "Bob"
  )
  UserRequests.updateUserById(userIdToUpdate, updatedUser)

  val userIdToDelete = 2L
  UserRequests.deleteUserById(userIdToDelete)
}</pre>



<p>And the corresponding result would be something like this:</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="">...
All Users: [UserResponse(userId=2, userName=User #2)]
...
User created successfully
...
All Users: [UserResponse(userId=2, userName=User #2), UserResponse(userId=7, userName=Mark)]
...
User with ID 2: UserResponse(userId=2, userName=User #2)
...
User updated successfully
...
User deleted successfully</pre>



<p>I’ve skipped the logs because they are not important for this.&nbsp;</p>



<h2 class="wp-block-heading" id="h-web-sockets">Web Sockets</h2>



<p>So, here&#8217;s the fun part. <strong>There is no Content Negotiation for the Web Sockets</strong> 🙁 </p>



<p>Nonetheless, there is such thing as <strong>contentConverter</strong> for WebSockets:</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="">private val client = HttpClient(CIO).config {
  install(WebSockets) {
    contentConverter = KotlinxWebsocketSerializationConverter(
      Json
    )
  }
}</pre>



<p>Basically, that&#8217;s it, now we can use <strong>sendSerialized()</strong> and <strong>receiveDeserialized()</strong> to send and receive data.</p>



<p>However, let&#8217;s focus more on manual implementation for the sake of understanding. Here we have classes to represent our messages:</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="">@Serializable
abstract class Message {
  abstract val content: String
}

@Serializable
@SerialName("text")
class TextMessage(override val content: String) : Message()

@Serializable
@SerialName("system")
class SystemMessage(override val content: String, val systemInfo: String) : Message()

private val module = SerializersModule {
  polymorphic(Message::class) {
    subclass(TextMessage::class, TextMessage.serializer())
    subclass(SystemMessage::class, SystemMessage.serializer())
  }
}

val messagesFormat = Json {
  serializersModule = module
}</pre>



<p>We are going to use TextMessage to send to the server and SystemMessage to send back from the server. </p>



<p>To send a message we must serialize it to string. And to receive vice versa. Nothing difficult: </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="">@OptIn(ExperimentalSerializationApi::class)
private suspend fun DefaultClientWebSocketSession.receiveMessage() {
  try {
    for (message in incoming) {
      message as? Frame.Text ?: continue
      val deserializedMessage: Message =
        messagesFormat.decodeFromStream(message.data.inputStream())
      println("${deserializedMessage.content} // ${(deserializedMessage as? SystemMessage)?.systemInfo}")
    }
  } catch (e: Exception) {
    println("Error while receiving: " + e.localizedMessage)
  }
}

private suspend fun DefaultClientWebSocketSession.sendMessage(message: Message) {
  val serializedMessage = messagesFormat.encodeToString(message)
  try {
    send(serializedMessage)
  } catch (e: Exception) {
    println("Some error occur: " + e.localizedMessage)
    return
  }
}</pre>



<p>Here&#8217;s our simple server that going to get our message and send it back with some changes:</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="">routing {
  webSocket("/hello") {
    try {
      for (frame in incoming) {
        frame as? Frame.Text ?: continue
        val deserializedMessage: WebSocketSession.Message =
          WebSocketSession.messagesFormat.decodeFromStream(frame.data.inputStream())
        val newMessageText = deserializedMessage.content + " - from Client"
        val serializedMessage = WebSocketSession.messagesFormat.encodeToString&lt;WebSocketSession.Message>(
          WebSocketSession.SystemMessage(
            content = newMessageText,
            systemInfo = "Important"
          )
        )
        Connection(this).session.send(serializedMessage)
      }
    } catch (e: Exception) {
      println(e.localizedMessage)
    }
  }
}</pre>



<p>The final part is to test it. We simply connect it to our already existing server:</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 main() {
  embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
    configureUserRoutes()
    configureSerialization()
    configureSockets()
  }.start(wait = true)
}</pre>



<p>And now run the client, for example, I’ve created this one:</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 connectWebSocket() {
  client.webSocket(
    host = "0.0.0.0",
    port = 8080,
    path = "/hello"
  ) {
    launch { sendMessage(TextMessage("Good morning!")) }
    launch { receiveMessage() }
    delay(2000)
    launch { sendMessage(TextMessage("Hello!")) }
    launch { receiveMessage() }
    delay(2000)
    println("Connection closed. Goodbye!")
    client.close()
  }
}

runBlocking {
  WebSocketSession.connectWebSocket()
}</pre>



<p>Here’s the results:</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="">2023-12-01 15:46:26.104 [DefaultDispatcher-worker-4] TRACE io.ktor.websocket.WebSocket - Sending Frame TEXT (fin=true, buffer len = 41) from session io.ktor.websocket.DefaultWebSocketSessionImpl@2e8ab815
2023-12-01 15:46:26.110 [DefaultDispatcher-worker-6] TRACE io.ktor.websocket.WebSocket - WebSocketSession(StandaloneCoroutine{Active}@4ecfdc65) receiving frame Frame TEXT (fin=true, buffer len = 82)
Good morning! - from Client // Important
2023-12-01 15:46:28.094 [DefaultDispatcher-worker-6] TRACE io.ktor.websocket.WebSocket - Sending Frame TEXT (fin=true, buffer len = 34) from session io.ktor.websocket.DefaultWebSocketSessionImpl@2e8ab815
2023-12-01 15:46:28.097 [DefaultDispatcher-worker-3] TRACE io.ktor.websocket.WebSocket - WebSocketSession(StandaloneCoroutine{Active}@4ecfdc65) receiving frame Frame TEXT (fin=true, buffer len = 75)
Hello! - from Client // Important
Connection closed. Goodbye!</pre>



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



<p>And that&#8217;s all for this article about <strong>kotlinx.serialization with Ktor</strong>. </p>



<p>If you would like to download the full source code, then you can find it in <a href="https://github.com/codersee-blog/kotlin-ktor-kotlinx-serialization" target="_blank" rel="noreferrer noopener">this GitHub repository</a>. </p>



<p>Lastly, thank you for being here, and happy to hear your feedback <strong>in the comments section below</strong>!</p>
<p>The post <a href="https://blog.codersee.com/how-to-use-kotlinx-serialization-with-ktor-and-kotlin/">How To Use kotlinx.serialization with Ktor and Kotlin?</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/how-to-use-kotlinx-serialization-with-ktor-and-kotlin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>kotlinx.serialization in Kotlin- All You Need To Know</title>
		<link>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/</link>
					<comments>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/#respond</comments>
		
		<dc:creator><![CDATA[Peter Lantukh]]></dc:creator>
		<pubDate>Tue, 12 Dec 2023 06:00:00 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[kotlinx]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9008417</guid>

					<description><![CDATA[<p>In this article, we will cover the most important scenarios of kotlinx.serialization in Kotlin and how to use it to your advantage.</p>
<p>The post <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/">kotlinx.serialization in Kotlin- All You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you are working with Kotlin, then it is a matter of time before you will face a need to <strong>serialize </strong>and <strong>deserialize </strong>your data.&nbsp;In this topic, I am going to cover the most important scenarios of <strong>kotlinx.serialization in Kotlin</strong> and how to use it to your advantage in your projects.</p>



<p>If you haven&#8217;t heard about it, then Kotlin Serialization is a <strong>cross-platform</strong> and multi-format framework built for this specific needs. It can be used with practically any Kotlin-based project, such as Android applications, Ktor applications, and Multiplatform (Common, JS, Native).&nbsp;</p>



<h2 class="wp-block-heading" id="h-setting-up">Setting Up</h2>



<p>To set up kotlinx.serialization in our project, we must add the following lines in your <strong>build.gradle.kts</strong>. </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="">plugins {

    kotlin("jvm") version "1.9.20" // or kotlin("multiplatform")

    kotlin("plugin.serialization") version "1.9.20"

}</pre>



<p>This will add the plugin. </p>



<p>Following, let&#8217;s add the implementation of the library itself:</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="">repositories {

    mavenCentral()

}

dependencies {

    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1")

}</pre>



<p>Now we&#8217;re ready to go!</p>



<h2 class="wp-block-heading" id="h-basic-serialization">Basic Serialization</h2>



<h3 class="wp-block-heading" id="h-simple-objects">Simple Objects</h3>



<p>You may not used this library yourself but you might have seen a <strong>@Serializable</strong> annotation before. </p>



<p>This is practically all we&#8217;re going to need to set up a serialization for a particular class, like this:&nbsp;</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="">@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>Now, to manually serialize it, we only need to use a <strong>Json.encodeToString()</strong>. </p>



<p>For 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="">val data = User(userId = 1, userName = "Alice")
println(
  Json.encodeToString(data)
)</pre>



<p>The output would be the following:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice"}</pre>



<p>On the other hand, to deserialize something, we&#8217;ll use <strong>Json.decodeFromString()</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="">val data = """  
  {
    "userId": 1,
    "userName":"Alice"
  }
"""  

println(
  Json.decodeFromString(
    User.serializer(), 
    data
  )
)</pre>



<p>The output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=Alice)</pre>



<p>kotlinx.serialization has also some useful functions to work with <strong>InputStream</strong> rather than with <strong>String</strong>. However, they are experimental at the moment and require using <strong>@OptIn(ExperimentalSerializationApi::class)</strong>.  </p>



<p>What am I talking about here? The <strong>Json.encodeFromStream()</strong> and <strong>Json.decodeFromStream()</strong>, which come in handy when we are dealing with Files.</p>



<p>Let&#8217;s take a look at how we can get data from the file without reading it and converting it to String. It saves lots of computation time, particularly on a big scale:</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="">@OptIn(ExperimentalSerializationApi::class)
fun deserializeFile(file: File): User {
  return Json.decodeFromStream(
    User.serializer(),
    file.inputStream()
  )
}</pre>



<p>Similarly, to encode it to a file we will use the <strong>encodeToStream</strong>:&nbsp;</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="">@OptIn(ExperimentalSerializationApi::class)
fun serializeFile(user: User, file: File) {
  Json.encodeToStream(
    User.serializer(),
    user,
    file.outputStream()
  )
}</pre>



<h3 class="wp-block-heading" id="h-nested-referenced-objects">Nested(Referenced) Objects</h3>



<p>As the next step, let&#8217;s talk about <strong>nested serialization</strong>. </p>



<p>Highly likely, that some of your classes have a property that is another class. </p>



<p>In such a case, there is practically no difference from the previous section, just all of our classes have to have a <strong>@Serializable</strong> annotation:</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="">@Serializable
data class Profile(
  val id: Int,
  val user: User
)

@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>Let&#8217;s check it out like this:</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 originalProfile = Profile(
  id = 123, 
  user = User(userId = 1, userName = "Alice")
)
  
println( 
  Json.encodeToString(
    Profile.serializer(), 
    originalProfile
  )
)  

val jsonString = """  
  {
    "id":123,
    "user": {
      "userId": 1,
      "userName":"Alice"
    }
  }
"""  

val deserializedProfile = Json.decodeFromString(
  Profile.serializer(), 
  jsonString
)
  
println(deserializedProfile)</pre>



<p>The output:</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="">{"id":123,"user":{"userId":1,"userName":"Alice"}}
Profile(id=123, user=User(userId=1, userName=Alice))</pre>



<h3 class="wp-block-heading" id="h-lists">Lists</h3>



<p>To serialize the whole List, we can use the <strong>ListSerializer</strong> constructor to create a serializer for any type of list, as long as <strong>we provide a serializer for the element type</strong>. </p>



<p>For 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="">val originalUsers = listOf(
  User(userId = 1, userName = "Alice"),
  User(userId = 2, userName = "Bob")
)  

println(
  Json.encodeToString(
    ListSerializer(User.serializer()), 
    originalUsers
  )
)  

val jsonString = """ 
  [
    {"userId":1,"userName":"Alice"},
    {"userId":2,"userName":"Bob"}
  ] 
"""  

val deserializedUsers = Json.decodeFromString(
  ListSerializer(User.serializer()), 
  jsonString
)  

println(deserializedUsers)</pre>



<p>That code will give us:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[{"userId":1,"userName":"Alice"},{"userId":2,"userName":"Bob"}]
[User(userId=1, userName=Alice), User(userId=2, userName=Bob)]</pre>



<h3 class="wp-block-heading" id="h-generics">Generics</h3>



<p>Basically, generics serialization works the same as nested objects. </p>



<p>The kotlinx.serialization has type-polymorphic behavior, which means that JSON relies on the actual type parameter. It will be compiled successfully if the actual generic type is a serializable class. </p>



<p>To check that, let&#8217;s modify our classes:</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="">@Serializable
data class Profile&lt;T>(
  val id: T,
  val user: Wrapper&lt;T>
)

@Serializable
data class Wrapper&lt;T>(val contents: T)</pre>



<p>Now we can check how it will work with different T for user fields:</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 profile1 = Profile(
  1, 
  Wrapper(
    User(userId = 1, userName = "Alice")
  )
)  
val profile2 = Profile(
  2, 
  Wrapper(42)
)  
  
val jsonProfile1 = Json.encodeToString(profile1)  
val jsonProfile2 = Json.encodeToString(profile2)  
  
println(jsonProfile1)  
println(jsonProfile2)  
  
val jsonString1 = """ 
  {
    "id": 1,
    "user": {
      "contents": {
        "userId": 1,
        "userName": "Alice"
      }
    }
  } 
"""  
val jsonString2 = """ 
  {
    "id": 2,
    "user": {
      "contents": 42
    }
  } 
"""  
  
val deserializedProfile1 = Json.decodeFromString(
  Profile.serializer(
    User.serializer()
  ),
  jsonString1
)  
val deserializedProfile2 = Json.decodeFromString(
  Profile.serializer(
    Int.serializer()
  ), 
  jsonString2
)  
  
println(deserializedProfile1)  
println(deserializedProfile2)</pre>



<p>There will be the following output:&nbsp;</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="">{"id":1,"user":{"contents":{"userId":1,"userName":"Alice"}}}
{"id":2,"user":{"contents":42}}
Profile(id=1, user=Wrapper(contents=User(userId=1, userName=Alice)))
Profile(id=2, user=Wrapper(contents=42))</pre>



<h2 class="wp-block-heading" id="h-customizing-serialization-and-deserialization">Customizing serialization and deserialization</h2>



<p>In this paragraph, we are gonna talk about making your objects a little bit appealing with variable behavior to adjust our specific needs.</p>



<h3 class="wp-block-heading" id="h-custom-names">Custom names</h3>



<p>As you have noticed, the basic name of a field is taken by default. </p>



<p>To create a custom name, the only thing we need is a <strong>@SerialName</strong> annotation:</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="">@Serializable
data class User(
  @SerialName("id") val userId: Int,
  @SerialName("login") val userName: String
)</pre>



<p>Now let&#8217;s use it as we used in the example at the beginning:</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 data = User(userId = 1, userName = "Alice")
println(
  Json.encodeToString(data)
)</pre>



<p>We&#8217;ll get:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":1,"login":"Alice"}</pre>



<p>But we must be careful- this works both ways. </p>



<p>After the change, we must make sure that the incoming JSON contains the names that we mentioned in the <strong>@SerialName</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="">val data = """{"id":1,"login":"Alice"}"""         //correct
val data = """{"userId":1,"userName":"Alice"}"""  //wrong</pre>



<h3 class="wp-block-heading" id="h-default-values">Default values</h3>



<p>Now things get a little bit trickier. Default values are not encoded by default. </p>



<p>So, if we want them to, we need the <strong>@EncodeDefault</strong> annotation:</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="">@Serializable
data class User(
  val userId: Int,
  @EncodeDefault val userName: String = "user"
)</pre>



<p>This way, we could omit a userName and the serialization library will use the default value:</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 data = User(userId = 1)
println(
  Json.encodeToString(data)
)</pre>



<p>Let&#8217;s see:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"user"}</pre>



<p>Excellent, works as expected!</p>



<p>But here is a different situation. What if we want to deserialize a JSON with some optional fields? </p>



<p>For it to compile properly, we must provide a default value for these fields:</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="">@Serializable
data class User(
  val userId: Int,
  val userName: String = "user"
)</pre>



<p>Now we can deserialize an object like this:&nbsp;</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 data = """
  {
    "userId": 1
  }
"""
  
println(
  Json.decodeFromString(
    User.serializer(),
    data
  )
)</pre>



<p>Output:&nbsp;</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="">User(userId=1, userName=user)</pre>



<p>On the other hand, if we want an optional field to be present in JSON, we may use a <strong>@Required</strong> annotation:</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="">@Serializable
data class User(
  val userId: Int,
  @Required val userName: String = "user"
)</pre>



<p>If we use this class with the code before, <strong>we will get an error</strong>, which can be useful in some scenarios:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Exception in thread &#8220;main&#8221; kotlinx.serialization.MissingFieldException: Field &#8216;userName&#8217; is required for type with serial name &#8216;com.example.User&#8217;, but it was missing</cite></blockquote>



<h3 class="wp-block-heading" id="h-nulls">Nulls</h3>



<p>Kotlin&#8217;s language is known for its type safety. The kotlinx.serialization knows it as well. </p>



<p>We cannot decode a null value into a non-nullable property or we get an exception. For example, for this 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="">@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>We cannot expect to serialize this object below:</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 data = """
  {
    "userId": 1,
     "userName": null
  }
"""
  
println(
  Json.decodeFromString(
    User.serializer(),
    data
  )
)</pre>



<p>It will result in an error.</p>



<p>To avoid it, we should do this instead:</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="">@Serializable
data class User(
  val userId: Int,
  val userName: String?
)</pre>



<p>This time, our result will be:&nbsp;</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="">User(userId=1, userName=null)</pre>



<p>As we can see, default values are not encoded by default. </p>



<p>So to get a missing property from JSON not as an optional but as a null value, we have to use <strong>@EncodeDefault</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="">@Serializable
data class User(
  val userId: Int,
  @EncodeDefault val userName: String? = null
)</pre>



<p>That is what we&#8217;ll see for our class:</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="">{"userId":1,"userName":null}</pre>



<p>However, if we forget the annotation, this is what we will get:</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="">{"userId":1}</pre>



<h2 class="wp-block-heading" id="h-advanced-serialization">Advanced Serialization</h2>



<p>This section is probably what you are looking for if you have a complex project. </p>



<p>These are the most sophisticated tricks of kotlinx.serialization, but the most useful, though. And now we are going to understand how they work.</p>



<p>From now on everything becomes more complex. So we have to establish ground rules and basic terms. </p>



<h3 class="wp-block-heading" id="h-what-exactly-is-a-polymorphism">What Exactly Is a Polymorphism?</h3>



<p>Polymorphism in Kotlin is the ability of an object or a function to have different forms or behaviors depending on the context. A polymorphic object can belong to different classes and respond to the same method call in different ways. </p>



<p>There are two types of polymorphism in Kotlin: <strong>compile-time</strong> and <strong>run-time</strong>:</p>



<ul class="wp-block-list">
<li><strong>Compile-time</strong> polymorphism, also known as static polymorphism, is achieved through function overloading. It allows the name of functions, i.e., the signature, to be the same but return type or parameter lists to be different.</li>



<li><strong>Run-time </strong>polymorphism, or <strong>dynamic </strong>polymorphism, is achieved through function overriding and inheritance. In the run-time polymorphism, the compiler resolves a call to overload methods at the runtime.</li>
</ul>



<p>But there is more. For serialization, we are going to talk about different approaches. To serialize an object, we should know what that object is in the first place and can its behavior can be changed. So there are 2 more types of polymorphism:</p>



<ul class="wp-block-list">
<li><strong>Closed</strong> polymorphism means that the behavior of an object is fixed and cannot be changed by subclasses or external factors.</li>



<li><strong>Open</strong> polymorphism means that the behavior of an object can be modified or extended by subclasses or external factors.<br>This is how the library sees polymorphism for the most part.</li>
</ul>



<h3 class="wp-block-heading" id="h-the-practice-part">The Practice Part</h3>



<p>First things first, let&#8217;s talk about <strong>closed </strong>polymorphism in kotlinx.serialization. </p>



<p>The first and the most obvious thing to do is to make all of our classes serializable:</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="">@Serializable
open class User(
  val userId: Int,
  val userName: String?
)

@Serializable
@SerialName("admin")
class Admin(
  val adminId: Int,
  val adminName: String?,
  val adminRole: String
) : User(adminId, adminName)</pre>



<p>Let&#8217;s check it out:&nbsp;</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 serializeAdmin() {
  val admin: User = Admin(
    adminId = 1,
    adminName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>Everything works as expected, our Admin is indeed a user:&nbsp;</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="">{"userId":1,"userName":"Alice"}</pre>



<p>But what will happen if we try to serialize an Admin object:</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 serializeAdmin() {
  val admin = Admin(
    adminId = 1,
    adminName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>Let&#8217;s find out:</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="">{"userId":1,"userName":"Alice","adminId":1,"adminName":"Alice","adminRole":"Boss"}</pre>



<p>So you have to keep that in mind. This may be a bit odd.<br>Following this, I want to cover <strong>sealed classes</strong> as well. Not because I&#8217;m a huge fan of it, which I am, but because of its natural behavior (we know all of its children at the runtime) that helps our process:</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="">@Serializable
sealed class User {
  abstract val userId: Int
  abstract val userName: String?
}

@Serializable
@SerialName("admin")
class Admin(
  override val userId: Int,
  override val userName: String?,
  val adminRole: String
) : User()</pre>



<p>We are going to check our first scenario:&nbsp;</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 serializeAdmin() {
  val admin: User = Admin(
    userId = 1,
    userName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>As expected, now we know the type of our user beforehand:&nbsp;</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="">{"type":"admin","userId":1,"userName":"Alice","adminRole":"Boss"}</pre>



<p>For a <strong>closed</strong> polymorphism, things get different. Now we have to create a <strong>SerializersModule</strong> and provide explicit subclasses that are to be serialized.</p>



<p>Let&#8217;s create an additional class to show this in action:</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="">@Serializable
abstract class User {
  abstract val userId: Int
  abstract val userName: String?
}

@Serializable
@SerialName("admin")
class Admin(
  override val userId: Int,
  override val userName: String?,
  val adminRole: String
) : User()

@Serializable
@SerialName("guest")
class Guest(
  override val userId: Int,
  override val userName: String?,
  val guestEmail: String?
) : User()</pre>



<p>Now comes the module:</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 module = SerializersModule {
  polymorphic(User::class) {
    subclass(Admin::class, Admin.serializer())
    subclass(Guest::class, Guest.serializer())
  }
}</pre>



<p>We&#8217;ve used a <strong>Json</strong> instance for our needs before. Now we have to create a specific instance with our module:</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 format = Json { serializersModule = module }</pre>



<p>With that done, let&#8217;s check 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="">fun serializeAdmin() {
  val admin: User = Admin(
    userId = 1,
    userName = "Alice",
    adminRole = "Boss"
  )
  val guest: User = Guest(
    userId = 1,
    userName = "Alice",
    guestEmail = "guest@email.com"
  )

  println(format.encodeToString(admin))
  println(format.encodeToString(guest))
}</pre>



<p>And this time, we get the following results:&nbsp;</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="">{"type":"admin","userId":1,"userName":"Alice","adminRole":"Boss"}
{"type":"guest","userId":1,"userName":"Alice","guestEmail":"guest@email.com"}</pre>



<p>We can serialize classes as long as we provide corresponding subclasses. </p>



<p>Of course, there is a lot to cover, for example, multiple superclasses or interfaces. But let&#8217;s stop here, maybe I&#8217;ll cover it explicitly in the other article. (Let me know if you are interested in this 🙂 ) </p>



<h3 class="wp-block-heading" id="h-custom-serializers">Custom serializers</h3>



<p>For some classes, happens that the default serialization method does not fulfill our needs. Or we want to create one that reflects a unique class utilization approach. For this purpose, <strong>custom serializers</strong> are our best friends. The most common examples are Date and Color. I&#8217;m gonna focus on Date.</p>



<p>Basically, there are 3 main parts of our custom serializer. Let&#8217;s check how the serializer for Date might look like:</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="">object DateSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>We can already see all the necessary parts.</p>



<ul class="wp-block-list">
<li>The <strong>serialize</strong> function is used to turn an object into a sequence of simple values. It takes an Encoder and a value as inputs. It calls the encodeXxx functions of the Encoder to make the sequence. There is a different encodeXxx function for each simple type.</li>



<li>The <strong>deserialize</strong> function is used to turn a sequence of simple values back into an object. It takes a Decoder as input and returns a value. It calls the decodeXxx functions of the Decoder to get the sequence. These functions match the encodeXxx functions of the Encoder.</li>



<li>The <strong>descriptor</strong> property is used to tell how the encodeXxx and decodeXxx functions work. This helps the format to know what methods to use. Some formats can also use it to make a schema for the data.</li>
</ul>



<p>For our purposes, we can simplify the class. If there is no particular need in the <strong>descriptor</strong>, we can use a <strong>@Serializer(forClass = …)</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="">@Serializer(forClass = Date::class)
object DateSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>To implement our custom serializer we should use a <strong>@Serializable(with = …)</strong> annotation for the corresponding property:</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="">@Serializable
data class Event(
  val name: String,
  @Serializable(with = DateSerializer::class)
  val date: Date
)</pre>



<p>Let&#8217;s see that in action:&nbsp;</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 event = Event("Birthday Party", Date())  

val json = Json.encodeToString(event)  

println(json)</pre>



<p>With the result:&nbsp;</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="">{"name":"Birthday Party","date":"2023-11-23 T 17:12:36.069+0300"}</pre>



<p>As we can see, it has successfully been serialized to the desired date format.</p>



<h3 class="wp-block-heading" id="h-contextual-serialization">Contextual serialization</h3>



<p>Sometimes we need to change how we write objects as JSON at run-time, not just at compile-time, as we spoke before. This is called contextual serialization. </p>



<p>We can use the <strong>@Contextual</strong> annotation on a class or a property to tell Kotlin to use the ContextualSerializer class. This class will choose the right serializer for the object based on the context. We are going to use the previous serializer:</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="">object DateAsStringSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>And our class will be looking like this:</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="">@Serializable
data class Event(
  val name: String,
  @Contextual val date: Date
)</pre>



<p>Now we need to create a <strong>SerializersModule</strong> in which we need to specify a serializers should be used for our contextually-serializable classes. </p>



<p>We can simply wrap our serializer in <strong>contextual</strong> function inside the module:</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="">private val module = SerializersModule {
  contextual&lt;Date>(DateAsStringSerializer)
}  </pre>



<p>Now we create a format out of Json with our module: </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 format = Json { serializersModule = module }</pre>



<p>Using our format of <strong>Json</strong> earlier, we&#8217;ll get our run-time serialization:&nbsp;</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 event = Event("Birthday Party", Date())  

val json = format.encodeToString(event)  

println(json)</pre>



<p>With an expected output:&nbsp;</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="">{"name":"Birthday Party","date":"2023-11-23 T 23:20:03.421+0300"}</pre>



<p></p>



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



<p>And that&#8217;s all for this article about <strong>serialization in Kotlin with kotlinx.serialization</strong>.</p>



<p>In the upcoming articles, we will get back to this topic and learn how to apply this knowledge with Ktor, so don&#8217;t forget to join the <a href="https://codersee.com/newsletter/">free newsletter</a> to not miss it!</p>



<p>Lastly, if you would like to learn more about kotlinx, then you can find lots of useful information on the official documentation of <a href="https://github.com/Kotlin/kotlinx.serialization" target="_blank" rel="noreferrer noopener">kotlinx</a>.&nbsp;</p>
<p>The post <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/">kotlinx.serialization in Kotlin- All You Need To Know</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/kotlinx-serialization-in-kotlin-all-you-need-to-know/feed/</wfw:commentRss>
			<slash:comments>0</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-04-19 11:13:44 by W3 Total Cache
-->