<?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>Serialization Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/serialization/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Tue, 02 Jan 2024 06: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>Serialization Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<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 fetchpriority="high" 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="(max-width: 474px) 100vw, 474px" /></figure>



<p>Post:</p>



<figure class="wp-block-image aligncenter size-full"><img 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="(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>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-02-25 18:19:52 by W3 Total Cache
-->