<?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>Kotlin Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/kotlin/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:50:30 +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>Kotlin Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Spring Boot 3 With Kotlin DSL. REST API Without Annotations</title>
		<link>https://blog.codersee.com/spring-boot-3-kotlin-dsl-rest-api-without-annotations/</link>
					<comments>https://blog.codersee.com/spring-boot-3-kotlin-dsl-rest-api-without-annotations/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 28 Mar 2023 06:00:42 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Kotlin DSL]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=6004437</guid>

					<description><![CDATA[<p>In this step-by-step guide, we will learn how to expose a REST API using Spring Boot 3, Kotlin, bean definition, and router DSL.</p>
<p>The post <a href="https://blog.codersee.com/spring-boot-3-kotlin-dsl-rest-api-without-annotations/">Spring Boot 3 With Kotlin DSL. REST API Without Annotations</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Hello ! 🙂 Continuing the DSL topic, I would like to show you how to expose a <strong>REST API</strong> using <strong>Spring Boot 3</strong>, <strong>Kotlin</strong>, <strong>bean definition</strong>, and <strong>router DSL</strong>.</p>



<p>In my <a href="https://blog.codersee.com/spring-boot-3-kotlin-router-dsl/" target="_blank" rel="noopener">previous article</a>, I showed you how the router DSL works and how to expose endpoints manually without needing any web-related annotations, like <em>@RequestMapping</em>,<em> @RestController</em>,<em> @RequestBody</em>, etc&#8230;</p>



<p>But is it possible to eliminate the annotations when defining beans? Yes, and in this article, I will prove to you that it&#8217;s possible to expose a REST API without any annotations, like @Component or any specialization.</p>



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



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



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


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



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



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



<p>Firstly, let&#8217;s navigate to <a href="https://start.spring.io/" target="_blank" rel="noopener">https://start.spring.io/</a> and generate a new project:</p>



<figure class="wp-block-image aligncenter"><img fetchpriority="high" decoding="async" width="1024" height="1024" src="http://blog.codersee.com/wp-content/uploads/2023/03/spring_initializr_screenshot_spring_boot_3_kotlin-1024x1024.png" alt="The image is a screenshot from the start.spring.io page, which shows the setting necessary in order to create a Spring Boot 3 project with Kotlin DSL." class="wp-image-6004441" srcset="https://blog.codersee.com/wp-content/uploads/2023/03/spring_initializr_screenshot_spring_boot_3_kotlin-1024x1024.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_initializr_screenshot_spring_boot_3_kotlin-300x300.png 300w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_initializr_screenshot_spring_boot_3_kotlin-150x150.png 150w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_initializr_screenshot_spring_boot_3_kotlin-768x768.png 768w, https://blog.codersee.com/wp-content/uploads/2023/03/spring_initializr_screenshot_spring_boot_3_kotlin.png 1261w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>As we can see, in order to expose a REST API with Spring Boot 3 and Kotlin DSL, we don&#8217;t have to add any additional dependencies. The only one is the Spring Web, which lets us build web applications.</p>



<p>Following, please import the project to your favorite IDE (like IntelliJ).</p>



<h2 class="wp-block-heading" id="h-3-add-models">3. Add Models</h2>



<p>Nextly, let&#8217;s create the <code class="EnlighterJSRAW" data-enlighter-language="raw">model</code> package and add 3 data classes to our application:</p>



<ul class="wp-block-list">
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">User</code>, which will transfer the data between the app and the data source,</li>



<li><code class="EnlighterJSRAW" data-enlighter-language="raw">UserDTO</code>, which will be serialized to JSON responses,</li>



<li>and <code class="EnlighterJSRAW" data-enlighter-language="raw">ErrorResponse</code>, shipping information about backend errors.</li>
</ul>



<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.kt
data class User(
  val id: Long? = null,
  val email: String,
  val name: String,
  val age: Int
)

// UserDTO.kt
data class UserDTO(
  val email: String,
  val name: String,
  val age: Int
)

// ErrorResponse.kt
data class ErrorResponse(
  val message: String
)
</pre>



<h2 class="wp-block-heading" id="h-4-implement-a-repository">4. Implement a Repository</h2>



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


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



<h3 class="wp-block-heading" id="h-4-1-add-userrepository-interface">4.1 Add UserRepository Interface</h3>



<p>Following, let&#8217;s introduce a <code class="EnlighterJSRAW" data-enlighter-language="raw">UserRepository</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface UserRepository {
  fun create(user: User): User
  fun findAll(): List&lt;User>
  fun findById(id: Long): User?
  fun updateById(id: Long, user: User): User?
  fun deleteById(id: Long)
}
</pre>



<p>And although oftentimes I skip this part for the simplicity of my tutorials, you will later see that working with interfaces, rather than implementations gives us much more flexibility. And in real-life scenarios, we should consider using them.</p>



<h3 class="wp-block-heading" id="h-4-2-add-implementation">4.2 Add Implementation</h3>



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



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class UserCrudRepository(
  private val dataSource: MutableMap&lt;Long, User>
) : UserRepository {

  override fun create(user: User): User {
    val lastId = this.dataSource.keys.max()
    val incrementedId = lastId + 1
    val updatedUser = user.copy(id = incrementedId)

    this.dataSource[incrementedId] = updatedUser

    return updatedUser
  }

  override fun findAll(): List&lt;User> =
    this.dataSource.values
      .toList()

  override fun findById(id: Long): User? =
    this.dataSource[id]

  override fun updateById(id: Long, user: User): User? =
    this.dataSource[id]
      ?.let { foundUser -> 
        val updatedUser = user.copy(id = foundUser.id)
        this.dataSource[id] = updatedUser
        updatedUser
      }

  override fun deleteById(id: Long) {
    this.dataSource.remove(id)
  }
}
</pre>



<p>As we can see, this class is just a dummy in-memory database, which will be operating on the <code class="EnlighterJSRAW" data-enlighter-language="raw">dataSource</code> map provided as a constructor argument.</p>



<h3 class="wp-block-heading" id="h-4-3-implement-datasource">4.3 Implement DataSource</h3>



<p>With that being done, let&#8217;s create a new object called <code class="EnlighterJSRAW" data-enlighter-language="raw">DataSource</code> (can go to the <code class="EnlighterJSRAW" data-enlighter-language="raw">config</code> package):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object DataSource {

  val devDataSource: MutableMap&lt;Long, User> = mutableMapOf(
    1L to User(1L, "email-1@gmail.com", "Name 1", 22),
    2L to User(2L, "email-2@gmail.com", "Name 2", 43),
    3L to User(3L, "email-3@gmail.com", "Name 3", 26),
    4L to User(4L, "email-4@gmail.com", "Name 4", 50)
  )

  val prodDataSource: MutableMap&lt;Long, User> = mutableMapOf(
    1L to User(1L, "prod-email-1@gmail.com", "Name 1", 22),
    2L to User(2L, "prod-email-2@gmail.com", "Name 2", 43),
    3L to User(3L, "prod-email-3@gmail.com", "Name 3", 26),
    4L to User(4L, "prod-email-4@gmail.com", "Name 4", 50)
  )

}
</pre>



<p>Well, in our application we will be dealing with dummy data.</p>



<p>However, in real life instead of two maps implementations, we would rather have a few implementations of UserRepository, for example:</p>



<ul class="wp-block-list">
<li>one, in-memory, which could be used for local development and testing,</li>



<li>the second, &#8220;real&#8221;, one, responsible for database connection.</li>
</ul>



<p>Either way, the purpose of this tutorial is to learn a bit more about Kotlin with bean definition DSL, and this setup will be useful in our considerations.</p>



<h2 class="wp-block-heading" id="h-5-configure-routing">5. Configure Routing</h2>



<p>In order to expose REST endpoints with Kotlin route DSL, we need to add two things:</p>



<ul class="wp-block-list">
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">UserHandler</code>&#8211; which normally would be a UserController when working with annotations,</li>



<li>custom <code class="EnlighterJSRAW" data-enlighter-language="raw">RouteFunctionDSL</code>&#8211; responsible for URL mappings.</li>
</ul>



<h3 class="wp-block-heading" id="h-5-1-add-userhandler">5.1 Add UserHandler</h3>



<p>Firstly, let&#8217;s add a <code class="EnlighterJSRAW" data-enlighter-language="raw">handler</code> package and implement the <code class="EnlighterJSRAW" data-enlighter-language="raw">UserHandler</code>:</p>



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

  fun createUser(
    request: ServerRequest
  ): ServerResponse {
    val userRequest = request.body(UserDTO::class.java)

    val createdUserResponse = userRepository.create(
      user = userRequest.toModel()
    )
      .toDTO()

    return ServerResponse.ok()
      .body(createdUserResponse)
  }

  fun findAllUsers(
    request: ServerRequest
  ): ServerResponse {
    val usersResponses = userRepository.findAll()
      .map(User::toDTO)

    return ServerResponse.ok()
      .body(usersResponses)
  }

  fun findUserById(
    request: ServerRequest
  ): ServerResponse {
    val id = request.pathVariable("id")
      .toLongOrNull()
      ?: return badRequestResponse("Invalid id")

    val userResponse = userRepository.findById(id)
      ?.toDTO()

    return userResponse
      ?.let { response ->
        ServerResponse.ok()
          .body(response)
      }
      ?: notFoundResponse(id)
  }

  fun updateUserById(
    request: ServerRequest
  ): ServerResponse {
    val id = request.pathVariable("id")
      .toLongOrNull()
      ?: return badRequestResponse("Invalid id")

    val userRequest = request.body(UserDTO::class.java)

    val updatedUser = userRepository.updateById(
      id = id,
      user = userRequest.toModel()
    )

    return updatedUser
      ?.let { response ->
        ServerResponse.ok()
          .body(response)
      }
      ?: notFoundResponse(id)
  }

  fun deleteUserById(
    request: ServerRequest
  ): ServerResponse {
    val id = request.pathVariable("id")
      .toLongOrNull()
      ?: return badRequestResponse("Invalid id")

    userRepository.deleteById(id)

    return ServerResponse.noContent()
      .build()
  }

  private fun badRequestResponse(reason: String): ServerResponse =
    ServerResponse.badRequest()
      .body(
        ErrorResponse(reason)
      )

  private fun notFoundResponse(id: Long): ServerResponse =
    ServerResponse.badRequest()
      .body(
        ErrorResponse("User with id: $id was not found.")
      )

}

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

private fun User.toDTO(): UserDTO =
  UserDTO(
    email = this.email,
    name = this.name,
    age = this.age
  )
</pre>



<p>As we can see, the handler has only one parameter of the <code class="EnlighterJSRAW" data-enlighter-language="raw">UserRepository</code>&nbsp; type. Thanks do that, <strong>we are not coupled with any implementation</strong>. Moreover, we gained flexibility and we can provide the implementation even on the fly when configuring beans.</p>



<p>Another interesting thing is the usage of <em>ServerRequests</em> and <em>ServerResponses</em>. When working with Spring Boot and Kotlin routes DSL, that&#8217;s how we deal with incoming requests and responses. And although for more details I redirect you to my previous article about this topic, I wanted to mention this because of one thing. As you can see- instead of throwing exceptions, which then Spring would translate to HTTP responses, we have the possibility to return our custom payload (and status codes, as well).</p>



<h3 class="wp-block-heading" id="h-5-2-implement-routing">5.2 Implement Routing</h3>



<p>Nevertheless, handler implementation is not sufficient. We have to instruct Spring about how HTTP requests should be handled.</p>



<p>To do so, let&#8217;s add the <code class="EnlighterJSRAW" data-enlighter-language="raw">Routes.kt</code> file inside the <code class="EnlighterJSRAW" data-enlighter-language="raw">config</code> package:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun appRouter(userHandler: UserHandler) = router {
  "/api".nest {
    "/users".nest {
      POST(userHandler::createUser)
      GET(userHandler::findAllUsers)
      GET("/{id}", userHandler::findUserById)
      PUT("/{id}", userHandler::updateUserById)
      DELETE("/{id}", userHandler::deleteUserById)
    }
  }
}
</pre>



<p>The <code class="EnlighterJSRAW" data-enlighter-language="raw">appRouter</code> function has one parameter of the <code class="EnlighterJSRAW" data-enlighter-language="raw">UserHandler</code> type, which we then use to provide references to functions inside it.</p>



<p>It&#8217;s worth mentioning that function references in Kotlin are an interesting syntactic sugar. However, if you prefer not to use them, you can always simply make use of brackets:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">POST { request -> userHandler.createUser(request) }
</pre>



<h2 class="wp-block-heading" id="h-6-kotlin-bean-definition-dsl">6. Kotlin Bean Definition DSL</h2>



<p>With all of that being done, we can finally learn <strong>how the Kotlin bean definition DSL work with Spring Boot 3</strong>.</p>



<h2 class="wp-block-heading" id="h-6-1-implement-beansconfig">6.1 Implement BeansConfig</h2>



<p>Firstly, let&#8217;s add a new file called <code class="EnlighterJSRAW" data-enlighter-language="raw">BeansConfig.kt</code> inside the <code class="EnlighterJSRAW" data-enlighter-language="raw">config</code> package:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val beans = beans {
  // beans definitions
}
</pre>



<p>The <code class="EnlighterJSRAW" data-enlighter-language="raw">beans {}</code> is nothing else than a function, which leverages the concept of <a href="https://kotlinlang.org/docs/type-safe-builders.html" target="_blank" rel="noopener">type-safe builders</a>.</p>



<p>Secondly, let&#8217;s add the <em>BeansConfig</em> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class BeansConfig : ApplicationContextInitializer&lt;GenericApplicationContext> {

  override fun initialize(context: GenericApplicationContext) =
    beans.initialize(context)

}
</pre>



<p>In order to register the beans in our application context, we have to invoke the <code class="EnlighterJSRAW" data-enlighter-language="raw">initialize()</code>.</p>



<p>Lastly, we need to make Spring aware of our initializer in <code class="EnlighterJSRAW" data-enlighter-language="raw">application.yaml</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">context:
  initializer:
    classes: com.codersee.kotlindsl.config.BeansConfig
</pre>



<h2 class="wp-block-heading" id="h-6-2-autowiring-by-type">6.2 Autowiring By Type</h2>



<p>As the next step, let&#8217;s see how we can define <em>UserHandler</em> and <em>router</em> beans and instruct Spring to<strong> autowire by type</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="">bean&lt;UserHandler>()
bean(::appRouter)
</pre>



<p>As we can see, we don&#8217;t even have to specify the types of particular parameters and Spring will take care of that automatically.</p>



<p>Moreover, with<strong> callable reference</strong>, we can define a bean with the <code class="EnlighterJSRAW" data-enlighter-language="raw">appRouter</code> top-level function.</p>



<h2 class="wp-block-heading" id="h-6-3-explicitly-specify-bean-type">6.3 Explicitly Specify Bean Type</h2>



<p>Of course, if we would like to specify the type of the bean manually or wire by name, then 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="">bean("myHandlerBean") {
  UserHandler(ref())
}
bean {
  appRouter(
    ref("myHandlerBean")
  )
}
</pre>



<p>And this time we simply make use of the ref function, which is responsible for getting a reference to beans by type (line 2), or by type and name (line 6).</p>



<h2 class="wp-block-heading" id="h-6-4-conditional-beans-based-on-profile">6.4 Conditional Beans Based On Profile</h2>



<p>Following, let&#8217;s see how we can differentiate the data source based on the profile 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="">profile("dev") {
  bean {
    UserCrudRepository(devDataSource)
  }
}

profile("prod") {
  bean {
    UserCrudRepository(prodDataSource)
  }
}
</pre>



<p>With this approach, beans defined inside the <code class="EnlighterJSRAW" data-enlighter-language="raw">profile()</code> won&#8217;t be created unless the specified profile is active.</p>



<p>Of course, we can activate profiles, for example inside the <code class="EnlighterJSRAW" data-enlighter-language="raw">application.yaml</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">spring:
  profiles:
    active: dev
</pre>



<h2 class="wp-block-heading" id="h-6-5-define-additional-beans-properties">6.5 Define Additional Beans Properties</h2>



<p>Following, let&#8217;s see how we can customize bean definitions:</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="">bean(
  name = "userHandler",
  scope = BeanDefinitionDsl.Scope.SINGLETON,
  isLazyInit = true,
  isPrimary = true,
  isAutowireCandidate = true,
  initMethodName = "",
  destroyMethodName = "",
  description = "description",
  role = BeanDefinitionDsl.Role.APPLICATION
)
</pre>



<p>As we can see, all parameters of the <code class="EnlighterJSRAW" data-enlighter-language="raw">bean</code> function have default values assigned.</p>



<p>Nevertheless, if we would like to set any values explicitly, then we can do it with ease.</p>



<h2 class="wp-block-heading" id="h-6-6-reading-environment-variables">6.6 Reading Environment Variables</h2>



<p>As the last thing, let&#8217;s see how we can read environment variables:</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 someVariable = env.systemEnvironment["SOME_VARIABLE"]
</pre>



<p>The systemEnvironment is nothing else than a <code class="EnlighterJSRAW" data-enlighter-language="raw">Map&lt;String, Object&gt;</code> instance, which is a result of <code class="EnlighterJSRAW" data-enlighter-language="raw">System.getenv()</code> invocation.</p>



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



<p>And that&#8217;s all for this tutorial about how to implement a REST API without annotations using Spring Boot 3, Kotlin bean definition, and router DSL.</p>



<p>I&#8217;m happy to<strong> hear your feedback</strong>&#8211; trust me, such a simple comment can motivate a lot and help me to work on my weaknesses 🙂</p>



<p>Of course, if you would like to see the source code for this article, then you can find it in this <a href="https://github.com/codersee-blog/kotlin-spring-boot-3-kotlin-bean-definition-router-dsl" target="_blank" rel="noopener">GitHub repository</a>.</p>
<p>The post <a href="https://blog.codersee.com/spring-boot-3-kotlin-dsl-rest-api-without-annotations/">Spring Boot 3 With Kotlin DSL. REST API Without Annotations</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/spring-boot-3-kotlin-dsl-rest-api-without-annotations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sending Transactional Emails Using Ktor, Kotlin, and MailerSend</title>
		<link>https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/</link>
					<comments>https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Thu, 02 Feb 2023 10:58:21 +0000</pubDate>
				<category><![CDATA[Ktor]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MailerSend]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=5504278</guid>

					<description><![CDATA[<p>In this, hands-on tutorial I will show you how to send transactional emails using Ktor, Kotlin, and MailerSend.</p>
<p>The post <a href="https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/">Sending Transactional Emails Using Ktor, Kotlin, and MailerSend</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Hello and welcome to my next, hands-on tutorial 🙂 This time, I would like to show you <strong>how to send transactional emails using Ktor, Kotlin, and MailerSend</strong>.</p>
<p>Sooner or later, every developer will have to implement email-sending functionality in their application and it&#8217;s worth checking out various solutions, to pick the one that will best meet our needs.</p>
<p>And although the term &#8220;transactional emails&#8221; sounds complicated, in this tutorial I will prove how easily we can use them with Ktor and Kotlin.</p>
<h2>Video Tutorial</h2>
<p>If you prefer <strong>video content</strong>, then check out my video:</p>
<div style="text-align: center; width: 80%; margin-left: 10%;">
<p><a href="https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2F29xM0SpzEEg%2Fhqdefault.jpg" alt="YouTube Video"></a></p>
</div>
<p>&nbsp;</p>
<p>If you find this content useful,<strong> please leave a subscription </strong> 😉</p>
<h2>Prerequisites</h2>
<p>Before we start, let&#8217;s see what exactly we will need for this tutorial.</p>
<p>First of all, we will need a <a href="https://www.mailersend.com?ref=fmebcn1eb2vc" target="_blank" rel="noopener">MailerSend account</a>. The free version will be fair enough for the purpose of learning and even simple projects.</p>
<blockquote><p>Note: the above link is a referral and if you will purchase any paid plan, I&#8217;ll get a small commission for that. To be clear: this fact affects the merits of this article in no way 🙂</p></blockquote>
<p>Additionally, <strong>you will need to have a domain, which you can verify</strong>. This is necessary, in order to work with any transactional email providers.</p>
<h2>Configure Domain in MailerSend</h2>
<p>I won&#8217;t go into much detail in this paragraph, because DNS settings will be dependent on your domain registrar. Nevertheless, let&#8217;s take look at how to add a new domain to MailerSend.</p>
<p>So, assuming we created our account and verified the email along with their policies, we should see the following:</p>
<p>&nbsp;</p>
<p><img decoding="async" class="size-full wp-image-5504282 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1.png" alt="Screenshot presents MailerSend dashboard." width="1427" height="738" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1.png 1427w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1-300x155.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1-1024x530.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_1-768x397.png 768w" sizes="(max-width: 1427px) 100vw, 1427px" /></p>
<p>&nbsp;</p>
<p>As the next step, let&#8217;s click the <strong>Start</strong> button next to the <em>&#8220;Add a sending domain&#8221;</em>:</p>
<p>&nbsp;</p>
<p><img decoding="async" class="alignnone size-full wp-image-5504283" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2.png" alt="Screenshot presents a modal, which allows user to enter a domain name, which we would like to register for transactional emails sending." width="1291" height="618" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2.png 1291w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2-300x144.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2-1024x490.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_2-768x368.png 768w" sizes="(max-width: 1291px) 100vw, 1291px" /></p>
<p>&nbsp;</p>
<p>Right here, let&#8217;s specify the domain name- <em>test.codersee.com</em> in my case- and confirm with the <strong>Add domain</strong> button.</p>
<p>Nextly, we should see the Domain verification modal:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504284 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3.png" alt="Screenshot presents domain verification modal with SPF, DKIM and RETURN-PATH settings to copy" width="891" height="1095" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3.png 891w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3-244x300.png 244w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3-833x1024.png 833w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_3-768x944.png 768w" sizes="auto, (max-width: 891px) 100vw, 891px" /></p>
<p>&nbsp;</p>
<p>As we can see, in order to verify our domain, we need to navigate to our domain registrar and modify the DNS settings using the values specified in the modal. When it&#8217;s done, let&#8217;s click the <strong>Check/Re-check</strong> now button.</p>
<blockquote><p>Note: DNS propagation can take some time, so don&#8217;t worry if you see the error messages (just like above). In such a case, give it some time and please get back to this page. MailerSend will send you an e-mail when everything is verified, as well.</p></blockquote>
<p>If everything succeeded, we should see the following page:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504285 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4.png" alt="" width="1410" height="706" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4.png 1410w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4-300x150.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4-1024x513.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_4-768x385.png 768w" sizes="auto, (max-width: 1410px) 100vw, 1410px" /></p>
<p>&nbsp;</p>
<p>One <strong>important note</strong> before we head to the next part. At this point, we <strong>will be able to send emails only to addresses and domains we previously verified</strong>&#8211; the e-mail address we use for registration and all addresses in a verified domain in our case.</p>
<p>Nevertheless, <strong>if you would like to send emails outside the domain, you will need to get approval</strong>.</p>
<h2>Generate API Key</h2>
<p>In order to send transactional emails with MailerSend in our Ktor app, we will need to generate a new <strong>API key</strong>.</p>
<p>To do so, let&#8217;s navigate to our domains (Email -&gt; Domains in the left sidebar) and click the manage button:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504288 size-full" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5.png" alt="Screenshot presents the test.codersee.com domain details page." width="1397" height="766" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5.png 1397w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5-300x164.png 300w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5-1024x561.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_5-768x421.png 768w" sizes="auto, (max-width: 1397px) 100vw, 1397px" /></p>
<p>&nbsp;</p>
<p>On this page, we can manage API tokens and configure plenty of other things, like webhooks or tracking.</p>
<p>Anyway, let&#8217;s click the Generate new token button:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504289 size-full" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_6.png" alt="Screenshot presents a MailerSend modal, where we can set a name for the API token and permission level for it." width="618" height="581" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_6.png 618w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_6-300x282.png 300w" sizes="auto, (max-width: 618px) 100vw, 618px" /></p>
<p>&nbsp;</p>
<p>As we can see, right here we can specify the name and access granted to the new token. And although for simplicity we will stick with &#8220;Full access&#8221;, in real-life scenarios we should always follow the principle of least privilege.</p>
<p>Finally, let&#8217;s click the Create token:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504290 size-full" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_7.png" alt="Screenshot shows a modal with a censored API token value " width="637" height="537" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_7.png 637w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_7-300x253.png 300w" sizes="auto, (max-width: 637px) 100vw, 637px" /></p>
<p>&nbsp;</p>
<p>As can be seen, the API token was created successfully and it&#8217;s time to save the value.</p>
<blockquote><p>Note: please persist this value securely and never share it with anyone!</p></blockquote>
<h2>Generate Ktor Project</h2>
<p>With all of that being done in MailerSend, we can finally switch to the Ktor &amp; Kotlin part of our tutorial about transactional emails.</p>
<p>As always, let&#8217;s navigate to <a href="https://start.ktor.io/" target="_blank" rel="noopener">https://start.ktor.io/</a> and specify desired project settings:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504291 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/01/mailersend_8.png" alt="The image shows Ktor Project Generator page, which we use to generate app skeleton, which then will be used to implement transactional emails with MailerSend." width="702" height="852" srcset="https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_8.png 702w, https://blog.codersee.com/wp-content/uploads/2023/01/mailersend_8-247x300.png 247w" sizes="auto, (max-width: 702px) 100vw, 702px" /></p>
<p>Following, let&#8217;s click the Add plugins (we don&#8217;t need anything else), generate the project, and import it to our IDE.</p>
<p>Nextly, let&#8217;s add the <strong>Ktor client</strong> and <strong>Jackson</strong> dependencies inside the build.gradle.kts:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">implementation("io.ktor:ktor-client-core-jvm:$ktor_version")
implementation("io.ktor:ktor-client-okhttp:$ktor_version")

implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-jackson:$ktor_version")
</pre>
<p>Of course, Jackson is not the only option here, and GSON, or kotlinx.serialization are well supported in Ktor, as well.</p>
<p>&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img loading="lazy" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<h2>Configure Client</h2>
<p>As the next step, let&#8217;s navigate to the<em> application.conf</em> file and add a custom MailerSend config:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">mailersend {
  token = ${MAILERSEND_TOKEN}
  baseUrl = ${MAILERSEND_BASE_URL}
}
</pre>
<p>This way, we can pass the token and URL values securely through environment variables. And although the token will be unique, for the baseUrl, let&#8217;s set <strong>https://api.mailersend.com/v1/</strong>.</p>
<p>Nextly, let&#8217;s create the <strong>MailerSendClient.kt</strong> file and put the following:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun Application.configureClient() {

  val token = environment.config.property("mailersend.token").getString()
  val baseUrl = environment.config.property("mailersend.baseUrl").getString()

  val mailerSendClient = HttpClient {
    install(ContentNegotiation) {
      jackson()
    }
  }

  runBlocking {
    // To be done in the next paragraphs
  }
}
</pre>
<p>As we can see, the above function reads configuration properties and installs the <span style="white-space: pre-wrap;"><em>ContentNegotiation</em> plugin using <em>Jackson</em>. Moreover, we&#8217;ve prepared the <em>runBlocking</em> block, where we will invoke our future functions. </span></p>
<p>Lastly, let&#8217;s navigate to the <em>Application.kt</em> file and make use of our config:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun Application.module() {
  configureClient()
}
</pre>
<p>At this point, we can run our application and verify that it is working, as expected. If we forget to set environment variables correctly, we should see something like this:</p>
<blockquote><p>Exception in thread &#8220;main&#8221; com.typesafe.config.ConfigException $ UnresolvedSubstitution: application.conf @ [&#8230;] Could not resolve substitution to a value: ${MAILERSEND_BASE_URL}</p></blockquote>
<h2>Send Simple Email</h2>
<p>With all of that done, we can finally start sending transactional emails. In this paragraph, we will learn how to send a simple email with MailerSend.</p>
<h3>Implement EmailRequest</h3>
<p>As the first step, let&#8217;s create a new data class called <strong>EmailRequest</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@JsonInclude(JsonInclude.Include.NON_NULL)
data class EmailRequest(
    val from: Recipient,
    val to: List&lt;Recipient&gt;,
    val subject: String,
    val text: String,
    val html: String,
    val variables: List&lt;Variable&gt;? = null
) {
    data class Recipient(
        val email: String,
        val name: String
    )

    data class Variable(
        val email: String,
        val substitutions: List&lt;Substitution&gt;
    ) {
        data class Substitution(
            @JsonProperty("var") val variable: String,
            val value: String
        )
    }
}
</pre>
<p>Basically, objects of this class will be serialized into JSONs when querying MailerSend API.</p>
<p>The <strong>@JsonInclude</strong> annotation states that if the value is set to null, then it should not be added to the JSON payload (so we won&#8217;t send <code class="EnlighterJSRAW" data-enlighter-language="raw">"whatever": null</code>) . Additionally, MailerSend requires us to send the &#8220;var&#8221; field inside the substitution. Nevertheless, <strong>var</strong> is a reserved keyword in Kotlin, so we have to make use of the <strong>@JsonProperty</strong>.</p>
<h3>Use Ktor Client to Perform Requests</h3>
<p>Following, let&#8217;s add a new function called <em>sendSingleEmail</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun sendSingleEmail(
  mailerSendClient: HttpClient,
  url: String,
  token: String,
  emailRequest: EmailRequest
): HttpResponse =
    mailerSendClient.post(url) {
      headers {
        append(HttpHeaders.Authorization, "Bearer $token")
      }
      contentType(ContentType.Application.Json)
      setBody(emailRequest)
    }
</pre>
<p>As we can see, this one is responsible for <strong>sending POST requests to the passed URL </strong>with the <strong>Authorization header</strong> containing the <strong>Bearer token</strong>.</p>
<p>Moreover, the function takes the EmailRequest as an argument, which makes it reusable.</p>
<h3>Send Transactional Client with Ktor Client</h3>
<p>Lastly, let&#8217;s implement the <em>sendSimpleMessage</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun sendSimpleMessage(
    mailerSendClient: HttpClient,
    baseUrl: String,
    token: String
) {
    val subject = "Hello from {\$company}!"
    val html = """
        Hello &lt;b&gt;{${'$'}name}&lt;/b&gt;, nice to meet you!
    """.trimIndent()
    val text = """
        Hello {${'$'}name}, nice to meet you!
    """.trimIndent()

    val emailRequest = EmailRequest(
        from = EmailRequest.Recipient(
            email = "example@test.codersee.com",
            name = "Codersee"
        ),
        to = listOf(
            EmailRequest.Recipient(
                email = "example@test.codersee.com",
                name = "Pjoter"
            )
        ),
        subject = subject,
        html = html,
        text = text,
        variables = listOf(
            EmailRequest.Variable(
                email = "example@test.codersee.com",
                substitutions = listOf(
                    EmailRequest.Variable.Substitution(
                        variable = "company",
                        value = "Codersee"
                    ),
                    EmailRequest.Variable.Substitution(
                        variable = "name",
                        value = "Piotr"
                    )
                )
            )
        )
    )

    val response = sendSingleEmail(
        mailerSendClient = mailerSendClient,
        url = "$baseUrl/email",
        token = token,
        emailRequest = emailRequest
    )

    if (response.status == HttpStatusCode.Accepted)
        println("Email sent successfully.")
    else
        println("Error when sending email.")
}
</pre>
<p>And although the above code snippet consists of a lot of lines, it&#8217;s definitely easier than it looks.</p>
<p>Firstly, we prepare the EmailRequest instance, which after serialization, will become this JSON:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">{
    "from": {
        "email": "example@test.codersee.com",
        "name": "Codersee"
    },
    "to": [
        {
            "email": "example@test.codersee.com",
            "name": "Pjoter"
        }
    ],
    "subject": "Hello from {$company}!",
    "html": "Hello &lt;b&gt;{$name}&lt;/b&gt;, nice to meet you!"
    "variables": [
        {
            "email": "example@test.codersee.com",
            "substitutions": [
                {
                    "var": "company",
                    "value": "Codersee"
                },
                {
                    "var": "name",
                    "value": "Piotr"
                }
            ]
        }
    ]
}
</pre>
<p>Whereas most of the fields a pretty descriptive, let&#8217;s take a look at one, important thing- <strong>variables</strong>.</p>
<p>As we can see, we can inject variables into the email subject, or content by simply specifying them with a dollar sign inside curly braces, for example: <em>{$someVariable}</em>. This way, we can specify dynamic values for each recipient, like name and company in our example.</p>
<p>In the next lines, we simply send the request to the MailerSend API, and if the response status code is <strong>202 Accepted</strong>, then the email was sent successfully:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504295 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_9.png" alt="Screenshot shows an example email send with MailerSend API using Ktor client." width="446" height="260" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_9.png 446w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_9-300x175.png 300w" sizes="auto, (max-width: 446px) 100vw, 446px" /></p>
<p>&nbsp;</p>
<p>Of course, in order to make it work, let&#8217;s invoke our function inside the <em>configureClient</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">runBlocking {
  sendSimpleMessage(mailerSendClient, baseUrl, token)
}
</pre>
<h2>Send Emails With Templates</h2>
<p>At this point, we already know how to send transactional emails with Ktor and MailerSend. Moreover, we&#8217;ve seen how to send HTML content, which is a great way to customize the template.</p>
<p>Nevertheless, if you&#8217;d like to learn how to <strong>make your life a bit easier</strong> and use a <strong>graphic builder for templates</strong>, then you&#8217;re gonna like this paragraph.</p>
<h3>Prepare Template Using MailerSend Builder</h3>
<p>As the first step, let&#8217;s navigate to the templates page: <a href="https://app.mailersend.com/templates" target="_blank" rel="noopener">https://app.mailersend.com/templates</a>.</p>
<p>Nextly, let&#8217;s click <strong>Create template</strong> button and select <strong>Drag &amp; drop</strong> editor option:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504296 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10.png" alt="Screenshot presents 3 options we can select when creating a new template: drag &amp; drop editor, rich-text editor and HTML editor." width="980" height="687" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10.png 980w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10-300x210.png 300w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_10-768x538.png 768w" sizes="auto, (max-width: 980px) 100vw, 980px" /></p>
<p>&nbsp;</p>
<p>This way, we&#8217;re redirected to the <strong>Template gallery</strong>, which contains ~50 predefined templates, which we can adjust to our needs. In this tutorial, we will select the <strong>Reset password</strong>:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5504297 aligncenter" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11.png" alt="Image presents MailerSend template gallery with highlited Reset passoword template." width="1250" height="763" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11.png 1250w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11-300x183.png 300w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11-1024x625.png 1024w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_11-768x469.png 768w" sizes="auto, (max-width: 1250px) 100vw, 1250px" /></p>
<p>&nbsp;</p>
<p>After we click <strong>Choose</strong>, we&#8217;re redirected to the builder page, where we can make adjustments:</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504298" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12.png" alt="Screenshot shows MailerSend template builder and edited template." width="500" height="563" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12.png 662w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-266x300.png 266w" sizes="auto, (max-width: 500px) 100vw, 500px" /></p>
<p>&nbsp;</p>
<p>As we can see, when using the builder, we need to encapsulate variables with <strong>double curly brackets</strong>.</p>
<p>When we finish, let&#8217;s click the <strong>Save &amp; Publish</strong> button and <strong>write down the Template ID</strong> on the next page- we will need it later.</p>
<h3>Adjust EmailRequest Class</h3>
<p>With that being done, let&#8217;s get back to the Ktor project and edit the EmailRequest class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@JsonInclude(JsonInclude.Include.NON_NULL)
data class EmailRequest(
    val from: Recipient,
    val to: List&lt;Recipient&gt;,
    val subject: String,
    @JsonProperty("template_id") val templateId: String,
    val personalization: List&lt;CustomPersonalization&gt;
) {
    data class Recipient(
        val email: String,
        val name: String
    )

    data class CustomPersonalization(
        val email: String,
        val data: PersonalizationData
    ) {
        data class PersonalizationData(
            val name: String,
            @JsonProperty("my_super_generated_code") val code: String
        )
    }
}
</pre>
<p>This time, instead of specifying the content manually, we simply pass the <strong>template identifier</strong> and a <strong>list of personalizations</strong>.</p>
<p>In our case, the desired JSON looks, as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "from": {
    "email": "example@test.codersee.com",
    "name": "Codersee"
  },
  "to": [
    {
      "email": "example@test.codersee.com",
      "name": "Pjoter"
    }
  ],
  "subject": "Please Reset Your Password",
  "templateId": "v69oxl587pzl785k",
  "personalization": [
    {
       "email": "example@test.codersee.com",
       "data": {
         "name": "Pjoter",
         "code": "f7fcc37c-4b7a-4919-aa91-a5ac7edd55d7"
       }
     }
  ]
}

</pre>
<h3>Implement Sending Functionality</h3>
<p>With all of that prepared, let&#8217;s implement the <em>sendMessageUsingTemplate</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun sendMessageUsingTemplate(
    mailerSendClient: HttpClient,
    baseUrl: String,
    token: String
) {
    val subject = "Please Reset Your Password"

    val emailRequest = EmailRequest(
        from = EmailRequest.Recipient(
            email = "example@test.codersee.com",
            name = "Codersee"
        ),
        to = listOf(
            EmailRequest.Recipient(
                email = "example@test.codersee.com",
                name = "Pjoter"
            )
        ),
        subject = subject,
        templateId = "v69oxl587pzl785k",
        personalization = listOf(
            EmailRequest.CustomPersonalization(
                email = "example@test.codersee.com",
                data = EmailRequest.CustomPersonalization.PersonalizationData(
                    name = "Pjoter",
                    code = UUID.randomUUID().toString()
                )
            )
        )
    )

    val response = sendSingleEmail(
        mailerSendClient = mailerSendClient,
        url = "$baseUrl/email",
        token = token,
        emailRequest = emailRequest
    )

    if (response.status == HttpStatusCode.Accepted)
        println("Email sent successfully.")
    else
        println("Error when sending email.")
</pre>
<p>As we can see, the logic itself remains almost exactly the same and the only thing, which changes, is the payload we send.</p>
<p>Lastly, let&#8217;s put the following in the <em>configureClient </em>and rerun the application:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">runBlocking {
  sendSimpleMessage(mailerSendClient, baseUrl, token)
}</pre>
<p>As a result, we should see the message &#8220;Email sent successfully.&#8221; and the following email in our inbox:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504301" src="http://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1.png" alt="Image shows an example email from inbox." width="550" height="556" srcset="https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1.png 786w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1-297x300.png 297w, https://blog.codersee.com/wp-content/uploads/2023/02/mailersend_12-1-768x777.png 768w" sizes="auto, (max-width: 550px) 100vw, 550px" /></p>
<h2>Handling ErrorsEmails With Templates</h2>
<p>I simply couldn&#8217;t finish this article about sending transactional emails with Ktor and MailerSend without showing <strong>how to handle errors</strong>.</p>
<p>And although we try our best to avoid them, sooner or later they will pop up. Thankfully, MailerSend API informs us in a pretty neat way about any issues. For example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
    "message": "The template_id must be an integer. (and 2 more errors)",
    "errors": {
        "template_id": [
            "The template_id must be an integer."
        ],
        "to.0.email": [
            "The to.0.email field is required."
        ],
        "variables.0.email": [
            "The variables.0.email field does not exist in to.*.email."
        ]
    }
}
</pre>
<h3>Create ErrorResponse</h3>
<p>As the first step, let&#8217;s implement the ErrorResponse class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class ErrorResponse(
  val message: String,
  val errors: Map&lt;String, List&lt;String&gt;&gt;
)
</pre>
<p>We will use this simple data class to deserialize JSON response into the object.</p>
<h3>Implement handleError</h3>
<p>Nextly, let&#8217;s add the <em>handleError</em> function:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">suspend fun handleError(response: HttpResponse) {
    val statusCode = response.status.value
    val errorBody =  response.body&lt;ErrorResponse&gt;()
    println("Email sending failed with status code $statusCode and message '${errorBody.message}'. Errors:")

    errorBody.errors.forEach { (fieldName, fieldErrors) -&gt;
        println("  * field name: [$fieldName]. Messages:")
        fieldErrors.forEach { error -&gt; println("    - $error") }
    }
}

</pre>
<p>As we can see, this function takes the HttpResponse from MailerSend API and parses the JSON into the ErrorResponse instance. Thanks to that we can iterate and display all the errors.</p>
<p>Of course, as the last step, we need to modify our conditional statement, to make use of this snippet:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">if (response.status == HttpStatusCode.Accepted)
  println("Email sent successfully.")
else 
  println("Error when sending email.")
</pre>
<h2>Sending Emails With Ktor And MailerSend Summary</h2>
<p>And that&#8217;s all for this article about <strong>how to send transactional emails using Ktor, Kotlin, and MailerSend</strong>.</p>
<p>As always, you can find the source code in this <a href="https://github.com/codersee-blog/kotlin-ktor-mailersend-transactional-emails" target="_blank" rel="noopener">GitHub repository.</a></p>
<p>Happy to hear your <strong>thoughts, feedback, or ideas in the comments</strong> 🙂</p>
<p>The post <a href="https://blog.codersee.com/sending-transactional-emails-ktor-kotlin-mailersend/">Sending Transactional Emails Using Ktor, Kotlin, and MailerSend</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/sending-transactional-emails-ktor-kotlin-mailersend/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot Console App With Kotlin</title>
		<link>https://blog.codersee.com/spring-boot-console-app-with-kotlin/</link>
					<comments>https://blog.codersee.com/spring-boot-console-app-with-kotlin/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 06 Dec 2022 06:00:50 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=5504027</guid>

					<description><![CDATA[<p>In this, step-by-step article, I will show you how to create a Spring Boot console app with Kotlin from scratch. </p>
<p>The post <a href="https://blog.codersee.com/spring-boot-console-app-with-kotlin/">Spring Boot Console App With Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>1. Introduction</h2>
<p>Hello! In this, short step-by-step guide, I will show you how to create a <strong>Spring Boot console app with Kotlin from scratch.</strong></p>
<p>In this article, we will learn:</p>
<ul style="list-style-type: none;">
<li>✅ What is the <strong>CommandLineRunner</strong> and how can it help us create a Spring Boot console app?</li>
<li>✅ How to implement an example Spring Boot console app with Kotlin</li>
</ul>
<h2>2. What is CommandLineRunner?</h2>
<p>As the first step, let&#8217;s take a minute to understand what exactly <strong>CommandLineRunner</strong> is. As the documentation states:</p>
<blockquote><p>Interface used to indicate that a bean should run when it is contained within a SpringApplication.</p></blockquote>
<p>In simple terms, the CommanLineRunner is an interface, which contains one method- <code class="EnlighterJSRAW" data-enlighter-language="java">void run(String... args) throws Exception</code>, which we can implement and which will be invoked automatically, without us having to do it manually.</p>
<p>Moreover, we can implement it multiple times and control the order of invocation using the @Order annotation or the Ordered interface.</p>
<h2>3. Create Project From Scratch</h2>
<p>With that being said, let&#8217;s generate a new Spring Boot Kotlin application. To do so, let&#8217;s navigate to the <a href="https://start.spring.io/" target="_blank" rel="noopener">Spring Initializr page</a> and specify the following settings:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-5504029 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/12/commandlinerunner_spring_initializr-1024x740.png" alt="The screenshot shows Spring Initializr page and settings necessary for this Spring Boot console app project." width="800" height="578" srcset="https://blog.codersee.com/wp-content/uploads/2022/12/commandlinerunner_spring_initializr-1024x740.png 1024w, https://blog.codersee.com/wp-content/uploads/2022/12/commandlinerunner_spring_initializr-300x217.png 300w, https://blog.codersee.com/wp-content/uploads/2022/12/commandlinerunner_spring_initializr-768x555.png 768w, https://blog.codersee.com/wp-content/uploads/2022/12/commandlinerunner_spring_initializr.png 1038w" sizes="auto, (max-width: 800px) 100vw, 800px" /></p>
<p>Basically, I would just like to emphasize that we don&#8217;t need any additional dependencies and the rest is totally up to you (and that I&#8217;m using the particular versions in case anything is deprecated in the future).</p>
<p>And once you pick your desired settings, please hit the Generate button and import the project to your IDE.</p>
<h2>4. Implement CommandLineRunner</h2>
<p>Finally, let&#8217;s open up our IDE and implement two classes called <em>WillBeInvokedFirst</em> and <em>WillBeInvokedSecond</em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@Component
@Order(1)
class WillBeInvokedFirst : CommandLineRunner {

  override fun run(vararg args: String) {
    print("Hello, ")
  }
}

@Component
@Order(2)
class WillBeInvokedSecond : CommandLineRunner {

  override fun run(vararg args: String) {
    println("World!")
  }
}</pre>
<p>As we can see, we have to do only three things to implement a command-line application:</p>
<ul>
<li>firstly, override the <em>run</em> method</li>
<li>secondly, annotate our classes with <strong>@Component</strong> annotation- to mark them as candidates for auto-detection</li>
<li>thirdly, specify the <strong>@Order</strong> annotation- this way we explicitly control, which <em>run</em> implementation is invoked first (lower value = higher priority)</li>
</ul>
<p>&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img loading="lazy" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<p>&nbsp;</p>
<p>Besides, no other changes are required. Nevertheless, please keep in mind that by default, the <em>CommandlineApplication.kt</em> file was added when creating a project:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@SpringBootApplication
class CommandlineApplication

fun main(args: Array&lt;String&gt;) {
  runApplication&lt;CommandlineApplication&gt;(*args)
}</pre>
<p>Finally, if we run the application we should see the following output:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">Hello, World!
</pre>
<h2>5. Summary</h2>
<p>And that would be all for this short article on how to create a<strong> Spring Boot console app with Kotlin</strong>. If you&#8217;d like to clone the project, then you can find it in this <a href="https://github.com/codersee-blog/spring-boot-kotlin-commandlinerunner" target="_blank" rel="noopener">GitHub repository</a>.</p>
<p>Let me know in the comments section if you enjoy such short articles solving particular problems. Of course as an addition to standard, long tutorials.</p>
<p>Finally, if you enjoyed this one, then you might be interested in other <a href="https://blog.codersee.com/tag/spring-boot/">Spring Boot articles</a> I created so far.</p>
<p>The post <a href="https://blog.codersee.com/spring-boot-console-app-with-kotlin/">Spring Boot Console App With 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/spring-boot-console-app-with-kotlin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>A Guide to MockK: a Mocking Library for Kotlin</title>
		<link>https://blog.codersee.com/a-guide-to-mockk-library/</link>
					<comments>https://blog.codersee.com/a-guide-to-mockk-library/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Mon, 12 Oct 2020 09:50:27 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">http://codersee.com/?p=1493</guid>

					<description><![CDATA[<p>In this article, I'd like to show you how to use MockK- an open-source mocking library for Kotlin- with JUnit 5.</p>
<p>The post <a href="https://blog.codersee.com/a-guide-to-mockk-library/">A Guide to MockK: a Mocking Library for Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p>There is no doubt, that testing is really crucial in the development process of any project. It allows us to automate the process of checking the functionality, as well as improves the quality of the code.</p>
<p>One of the techniques commonly used in unit testing is <strong>mocking</strong>. To put it in simple terms, mock objects are the objects that simulate the behavior of real objects.</p>
<p>In this article, I&#8217;d like to show you how to use <strong>MockK</strong>&#8211; an <a href="https://mockk.io/" target="_blank" rel="noopener noreferrer">open-source mocking library</a> for Kotlin- with <strong>JUnit 5</strong>.</p>
<h2 class="article-heading-main">2. Prepare the Code For Testing</h2>
<p>Before we will head to the testing part, let&#8217;s write the code, which we will be testing later:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">class ExampleClass {

    fun multiplyByTen(number: Int) = 10 * number

    fun publicFunction() = privateFunction()

    private fun privateFunction() = "Returned value"
}

class Injected {
    fun multiplyByFive(number: Int) = 5 * number
}

class ExampleClassWithDependency {

    lateinit var injected: Injected

    fun returnInjectedValue(number: Int) = injected.multiplyByFive(number)
}

object ExampleObject {
    fun concat(one: String, two: String) = one + two
}
</pre>
<p>As you can see, we&#8217;ve created a few simple classes and one object. Just for the record, a <strong>Kotlin object</strong> is a special singleton class- a class that has got only one instance.</p>
<h2 class="article-heading-main">3. Imports</h2>
<p>As the next step, let&#8217;s add the required dependencies to our project:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="groovy">  
  implementation("io.mockk:mockk:1.10.2")
  testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
  testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0")
</pre>
<p>&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img loading="lazy" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<p>&nbsp;</p>
<h2 class="article-heading-main">3. Using MockK library</h2>
<p>In this article, we will learn how to use <em>a few simple features</em> of the library. If you would like to learn more, I highly recommend checking out <a href="https://github.com/mockk/mockk" target="_blank" rel="noopener noreferrer">MockK&#8217;s Github repository</a>.</p>
<h3 class="article-heading-sub">3.1. Mocking</h3>
<p>Firstly, let&#8217;s see how to specify what exactly should be returned by the function of the mocked class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Mock a class`() {
        val exampleClass = mockk()

        every { exampleClass.publicFunction() } returns "Mocked value"

        val result = exampleClass.publicFunction()

        assertEquals("Mocked value", result)
    }
</pre>
<p>With this code, the <strong>&#8220;Mocked value&#8221;</strong> String will be returned for each invocation of the <strong>publicFunction</strong>.</p>
<p>Nextly, let&#8217;s mock a property of the class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Mock a property of the class`() {
        val injected = mockk()
        val exampleClass = ExampleClassWithDependency()
        exampleClass.injected = injected

        every { injected.multiplyByFive(any()) } returns 7

        val result = exampleClass.returnInjectedValue(10)

        assertEquals(7, result)
    }
</pre>
<p>This time, our result will be 7, even though the original function should return 50.</p>
<h3 class="article-heading-sub">3.2. Relaxed mock</h3>
<p>What happens if we do not specify the behavior of the invoked function? Let&#8217;s check this code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Example of MockKException`() {
        val exampleClass = mockk()

        exampleClass.publicFunction()
    }
</pre>
<p>The test failed throwing <strong>MockKException</strong> informing us that no answer has been found for the function we were trying to test.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Fix MockKException using relaxed mock`() {
        val exampleClass = mockk(relaxed = true)
        val defaultStringValue = ""

        assertEquals(defaultStringValue, exampleClass.publicFunction())
    }
</pre>
<p>To fix that, we can either specify explicitly the behavior or use a<strong> relaxed mock</strong>. A relaxed mock returns the default values for all the functions within the mocked class. As we can see above, the default String value returned by the function will be an <strong>empty String</strong>.</p>
<h3 class="article-heading-sub">3.3. Using Annotations</h3>
<p>If we would like to simplify the creation of the object, we can use annotations. As we are using JUnit5, we need to annotate our test class with <em><strong>@ExtendWith</strong></em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@ExtendWith(MockKExtension::class)
internal class ExampleClassTest
</pre>
<p>As the next step, let&#8217;s add two properties to it:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @MockK
    lateinit var annotatedMock: Injected

    @InjectMockKs
    var annotatedClass = ExampleClassWithDependency()
</pre>
<p>And create a new test:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Simplified property mock with annotation`() {
        every { annotatedMock.multiplyByFive(any()) } returns 7

        val result = annotatedClass.returnInjectedValue(10)

        assertEquals(7, result)
    }
</pre>
<p>With this approach, we eliminate the need to manually create the mock for each test.</p>
<h3 class="article-heading-sub">3.4. Spy The Object</h3>
<p>Sometimes, we would like to have the possibility to check the real behavior of the class, as well as a mocked one. For that case, we can use a spy:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Spy a class`() {
        val exampleClass = spyk()

        assertEquals("Returned value", exampleClass.publicFunction())
    }
</pre>
<p>As we can see here, the function returns the value that has been implemented in our code.</p>
<h3 class="article-heading-sub">3.5. Mock Private Function Behavior</h3>
<p>In our class implementation, <strong>publicFunction</strong> returns the value from <strong>privateFunction</strong>. Let&#8217;s check, how we can specify the behavior of the private function:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@Test
fun `Mock a private function`() {
val exampleClass = spyk(recordPrivateCalls = true)

every { exampleClass["privateFunction"]() } returns "Mocked value"

assertEquals("Mocked value", exampleClass.publicFunction())
}
</pre>
<h3 class="article-heading-sub">3.6. Mock an Object</h3>
<p>As we&#8217;ve told in the beginning, the Kotlin object is a special singleton class. To mock it, we will use <strong>mockkObject</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Mock an object`() {
        mockkObject(ExampleObject)

        every { ExampleObject.concat(any(), any()) } returns "Mocked value"

        val result = ExampleObject.concat("", "")
        assertEquals("Mocked value", result)
    }
</pre>
<p>Even though Kotlin allows us to have only one instance of the object class, the MockK library allows us to create <strong>multiple instances of its mocks</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin"> 
    @Test
    fun `Multiple mocked instances of object`() {
        val firstMock = mockk()
        val secondMock = mockk()

        every { firstMock.concat(any(), any()) } returns "One"
        every { secondMock.concat(any(), any()) } returns "Two"

        val firstResult = firstMock.concat("", "")
        val secondResult = secondMock.concat("", "")

        assertEquals("One", firstResult)
        assertEquals("Two", secondResult)
    }
</pre>
<h3 class="article-heading-sub">3.7. Capturing</h3>
<p>In our previous examples, we didn&#8217;t care about what arguments were passed to the stubbed methods. A technique called capturing allows us to validate what arguments has been passed:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Capture passed value`() {
        val exampleClassMock = mockk()
        val argumentSlot = slot()

        every { exampleClassMock.multiplyByTen(capture(argumentSlot)) } returns 5

        exampleClassMock.multiplyByTen(55)

        assertEquals(55, argumentSlot.captured)
    }
</pre>
<p>As we can see, the slot contains the captured value, which we have passed to our checked function.</p>
<h3 class="article-heading-sub">3.8. Verification</h3>
<p>If we would like to check how many times the function has been invoked, we can use verify:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">    @Test
    fun `Verify calls`() {
        val exampleClassMock = mockk()

        every { exampleClassMock.multiplyByTen(any()) } returns 5

        exampleClassMock.multiplyByTen(10)
        exampleClassMock.multiplyByTen(20)

        verify(exactly = 2) { exampleClassMock.multiplyByTen(any()) }
        confirmVerified(exampleClassMock)
    }
</pre>
<p>In the above example, we&#8217;ve used the <em><strong>exactly</strong></em> parameter to verify that the behavior happened exactly 2 times. If we would specify another number, the test would fail and inform us, that the verification failed.</p>
<h2 class="article-heading-introduction">4. Summary</h2>
<p>And that would be all for this article. We&#8217;ve learned how to use some basic features of the <strong>MockK library with JUnit5</strong>.</p>
<p>For the source code of the project, please visit our project on <a href="https://github.com/codersee-blog/kotlin-mockk" target="_blank" rel="noopener noreferrer"><strong>GitHub</strong></a>.</p>
<p>If you enjoyed this tutorial, I would be forever grateful if you would like to share some feedback with me through our <a href="https://www.facebook.com/codersee/" target="_blank" rel="noopener noreferrer"><strong>page</strong></a>, <a href="https://www.facebook.com/groups/622361565094117" target="_blank" rel="noopener noreferrer"><strong>group</strong></a>, or <strong><a href="http://codersee.com/contact/" target="_blank" rel="noopener noreferrer">contact</a> </strong>form. I highly appreciate all the comments and suggestions that I am getting from you.</p>
<p>The post <a href="https://blog.codersee.com/a-guide-to-mockk-library/">A Guide to MockK: a Mocking Library for 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/a-guide-to-mockk-library/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-05-14 03:15:24 by W3 Total Cache
-->