Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin_for_server-side_application_development.pdf

 Kotlin_for_server-side_application_development.pdf

Anton Arhipov

December 02, 2022
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. @antonarhipov
    Kotlin for server-side
    application development

    View full-size slide

  2. @antonarhipov

    View full-size slide

  3. 2011 - alternative JVM language

    View full-size slide

  4. 2011 - alternative JVM language
    Then - Android, JavaScript, LLVM, WASM…..

    View full-size slide

  5. 2011 - alternative JVM language
    Then - Android, JavaScript, LLVM, WASM…..
    2017 - O
    ffi
    cially supported for Android

    View full-size slide

  6. 2011 - alternative JVM language
    Multi-Platform Projects
    Then - Android, JavaScript, LLVM, WASM…..
    2017 - O
    ffi
    cially supported for Android

    View full-size slide

  7. What developers say about

    View full-size slide

  8. What developers say about
    Concise & modern

    View full-size slide

  9. What developers say about
    Concise & modern
    Null-safe

    View full-size slide

  10. What developers say about
    Concise & modern
    MPP, Kotlin/JS
    Null-safe

    View full-size slide

  11. What developers say about
    Concise & modern
    Coroutines!
    MPP, Kotlin/JS
    Null-safe

    View full-size slide

  12. What developers say about
    Concise & modern
    Coroutines!
    MPP, Kotlin/JS
    stdlib
    Null-safe

    View full-size slide

  13. Just use it once…

    View full-size slide

  14. Who uses Kotlin?
    for server-side application development

    View full-size slide

  15. Code sharing


    across clients

    View full-size slide

  16. Code sharing


    between frontend


    and backend

    View full-size slide

  17. https://youtu.be/4GkoB4hZUnw

    View full-size slide

  18. From monolith to microservices


    From Java to Kotlin


    Developer happiness


    View full-size slide

  19. https://youtu.be/7YJyPXjLdug

    View full-size slide

  20. https://youtu.be/7YJyPXjLdug
    In Kotlin, you can build a data model
    that’s going to match exactly how your
    GraphQL schema looks like

    View full-size slide

  21. Adobe: leveraging
    Kotlin Coroutines
    https://medium.com/adobetech/
    streamlining-server-side-app-
    development-with-kotlin-be8cf9d8b61a

    View full-size slide

  22. Adobe: leveraging
    Kotlin Coroutines
    https://medium.com/adobetech/
    streamlining-server-side-app-
    development-with-kotlin-be8cf9d8b61a

    View full-size slide

  23. Extreme code reuse


    with Kotlin Multiplatform

    View full-size slide

  24. Extreme code reuse


    with Kotlin Multiplatform
    Brave new world with microservices


    and happier developers!

    View full-size slide

  25. Extreme code reuse


    with Kotlin Multiplatform
    Brave new world with microservices


    and happier developers!
    Expressiveness and safety


    for building GraphQL APIs


    (with Java interoperability!)

    View full-size slide

  26. Extreme code reuse


    with Kotlin Multiplatform
    Brave new world with microservices


    and happier developers!
    Expressiveness and safety


    for building GraphQL APIs


    (with Java interoperability!)
    High-load, lock-free software


    with Kotlin Coroutines

    View full-size slide

  27. What framework(s) should I use?
    Libraries, build tools, etc?

    View full-size slide

  28. Hexagon
    KVision

    View full-size slide

  29. Spring with Kotlin

    View full-size slide

  30. import org.springframework.boot.autoconfigure.SpringBootApplication


    import org.springframework.boot.runApplication





    @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    View full-size slide

  31. import org.springframework.boot.autoconfigure.SpringBootApplication


    import org.springframework.boot.runApplication





    @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    View full-size slide

  32. import org.springframework.boot.autoconfigure.SpringBootApplication


    import org.springframework.boot.runApplication





    @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    View full-size slide

  33. import org.springframework.boot.autoconfigure.SpringBootApplication


    import org.springframework.boot.runApplication





    @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args)


    }


    @RestController


    class MessageResource(val service: MessageService) {


    @GetMapping


    fun index(): List = service.findMessages()


    @PostMapping


    fun post(@RequestBody message: Message) {


    service.post(message)


    }


    }


    View full-size slide

  34. @Service


    class MessageService(val db: MessageRepository) {


    fun findMessages(): List = db.findMessages()


    fun post(message: Message){


    db.save(message)


    }


    }


    interface MessageRepository : CrudRepository{


    @Query("select * from messages")


    fun findMessages(): List


    }


    @Table("MESSAGES")


    data class Message(@Id val id: String?, val text: String)


    View full-size slide

  35. @Service


    class MessageService(val db: MessageRepository) {


    fun findMessages(): List = db.findMessages()


    fun post(message: Message){


    db.save(message)


    }


    }


    interface MessageRepository : CrudRepository {


    @Query("select * from messages")


    fun findMessages(): List


    }


    @Table("MESSAGES")


    data class Message(@Id val id: String?, val text: String)


    View full-size slide

  36. @Service


    class MessageService(val db: MessageRepository) {


    fun findMessages(): List = db.findMessages()


    fun post(message: Message){


    db.save(message)


    }


    }


    interface MessageRepository : CrudRepository{


    @Query("select * from messages")


    fun findMessages(): List


    }


    @Table("MESSAGES")


    data class Message(@Id val id: String?, val text: String)


    View full-size slide

  37. @Service


    class MessageService(val db: MessageRepository) {


    fun findMessages(): List = db.findMessages()


    fun post(message: Message){


    db.save(message)


    }


    }


    interface MessageRepository : CrudRepository{


    @Query("select * from messages")


    fun findMessages(): List


    }


    @Table("MESSAGES")


    data class Message(@Id val id: String?, val text: String)


    Not to be used with JPA!

    View full-size slide

  38. https://stackover
    fl
    ow.com/questions/58127353/should-i-use-kotlin-data-class-as-jpa-entity
    Resources:
    https://kotlinexpertise.com/hibernate-with-kotlin-spring-boot/
    https://dzone.com/articles/kotlin-data-classes-and-jpa
    https://blog.codecentric.de/en/2017/06/kotlin-spring-working-jpa-data-classes/
    https://spring.io/guides/tutorials/spring-boot-kotlin/

    View full-size slide

  39. Important for starters

    View full-size slide

  40. Important for starters
    * Kotlin classes are
    fi
    nal by default

    View full-size slide

  41. Important for starters
    * Kotlin classes are
    fi
    nal by default
    * Compiler plugins to the rescue!

    View full-size slide

  42. Important for starters
    * Kotlin classes are
    fi
    nal by default
    * Compiler plugins to the rescue!
    * Data classes don’t play well with JPA

    View full-size slide

  43. Important for starters
    * Kotlin classes are
    fi
    nal by default
    * Compiler plugins to the rescue!
    * Data classes don’t play well with JPA
    * Use usual classes with JPA

    View full-size slide

  44. * Kotlin classes are
    fi
    nal by default
    * Compiler plugins to the rescue!
    * Data classes don’t play well with JPA
    * Use usual classes with JPA
    Important for starters
    * Use start.spring.io to generate con
    fi
    gs

    View full-size slide

  45. kotlin extensions

    View full-size slide

  46. println("hello".uuid())


    View full-size slide

  47. fun String.uuid(): String =


    UUID.nameUUIDFromBytes(this.encodeToByteArray()).toString()


    println("hello".uuid())


    View full-size slide

  48. fun String.uuid(): String =


    UUID.nameUUIDFromBytes(encodeToByteArray()).toString()


    println("hello".uuid())


    View full-size slide

  49. fun String.uuid() =


    UUID.nameUUIDFromBytes(encodeToByteArray()).toString()


    println("hello".uuid())


    View full-size slide

  50. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    View full-size slide

  51. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    View full-size slide

  52. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    RowMapper { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) },


    id)

    View full-size slide

  53. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    RowMapper { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) },


    id)

    View full-size slide

  54. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    RowMapper { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) },


    id)

    View full-size slide

  55. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    RowMapper { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) },


    id)
    RowMapper is a
    functional interface

    View full-size slide

  56. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) },


    id)
    “SAM conversion” is
    performed by the compiler

    View full-size slide

  57. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) },


    id)

    View full-size slide

  58. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    id,


    { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) })

    View full-size slide

  59. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    id,


    { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) })
    vararg is not at the last position

    View full-size slide

  60. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?",


    id,


    { rs, _
    ->
    Message(rs.getString("id"), rs.getString("text")) })
    Lambda expression is at the last position

    View full-size slide

  61. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    View full-size slide

  62. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    Passing trailing lambda as a
    parameter to the function

    View full-size slide

  63. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    View full-size slide

  64. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    This is an extension function


    For the existing Java class in the
    Spring framework

    View full-size slide

  65. @Service


    class MessageService(val db: JdbcTemplate) {


    fun findMessages(): List = db.query("select * from messages") { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun findMessageById(id: String): List =


    db.query("select * from messages where id = ?", id) { rs, _
    - >

    Message(rs.getString("id"), rs.getString("text"))


    }


    fun post(message: Message){


    db.update("insert into messages values ( ?, ? )",


    message.id
    ?:
    message.text.uuid(), message.text)


    }


    }


    View full-size slide

  66. extensions


    & Trailing lambdas

    View full-size slide

  67. fun String.uuid() =


    UUID.nameUUIDFromBytes(encodeToByteArray()).toString()


    View full-size slide

  68. fun String.uuid() =


    UUID.nameUUIDFromBytes(encodeToByteArray()).toString()


    fun applyAction(vararg s: String, action: (String)
    ->
    Unit) {


    s.forEach(action)


    }


    View full-size slide

  69. fun String.uuid() =


    UUID.nameUUIDFromBytes(encodeToByteArray()).toString()


    fun applyAction(vararg s: String, action: (String)
    ->
    Unit) {


    s.forEach(action)


    }


    fun main() {


    applyAction("hello", "bye") { s: String
    ->

    println(s.uuid())


    }


    }


    View full-size slide

  70. fun String.uuid() =


    UUID.nameUUIDFromBytes(encodeToByteArray()).toString()


    fun applyAction(vararg s: String, action: (String)
    ->
    Unit) {


    s.forEach(action)


    }


    fun main() {


    applyAction("hello", "bye") { s: String
    ->

    println(s.uuid())


    }


    }


    Note to self: open the IDE

    View full-size slide

  71. more kotlin extensions


    In spring

    View full-size slide

  72. class HtmlController(val messageService: MessageService) {


    @GetMapping("/")


    fun index(model: Model): String {


    val messages = messageService.latest()


    model.asMap()["messages"] = messages


    model.asMap()["lastMessageId"] = messages.lastOrNull()
    ?
    .
    id
    ?
    :
    ""


    return "chat"


    }


    }


    View full-size slide

  73. class HtmlController(val messageService: MessageService) {


    @GetMapping("/")


    fun index(model: Model): String {


    val messages = messageService.latest()


    model.asMap()["messages"] = messages


    model.asMap()["lastMessageId"] = messages.lastOrNull()
    ?
    .
    id
    ?
    :
    ""


    return "chat"


    }


    }


    View full-size slide

  74. class HtmlController(val messageService: MessageService) {


    @GetMapping("/")


    fun index(model: Model): String {


    val messages = messageService.latest()


    model.asMap()["messages"] = messages


    model.asMap()["lastMessageId"] = messages.lastOrNull()
    ?
    .
    id
    ?
    :
    ""


    return "chat"


    }


    }


    View full-size slide

  75. class HtmlController(val messageService: MessageService) {


    @GetMapping("/")


    fun index(model: Model): String {


    val messages = messageService.latest()


    model["messages"] = messages


    model["lastMessageId"] = messages.lastOrNull()
    ?.
    id
    ?:
    ""


    return "chat"


    }


    }


    View full-size slide

  76. Type-safe builders
    A.k.a. dsl

    View full-size slide

  77. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    addInitializers(beans)


    }


    }


    View full-size slide

  78. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    this.addInitializers(beans)


    }


    }


    “this” refers to SpringApplication instance

    View full-size slide

  79. val beans = beans {


    bean {


    CommandLineRunner {


    println("start data initialization
    .. .
    ")


    val repository = ref()


    repository.save(Message(text = "this is the first message!"))


    repository.save(Message(text = "this is the second"))


    }


    }


    }
    @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    this.addInitializers(beans)


    }


    }


    View full-size slide

  80. @SpringBootApplication


    class DemoApplication


    fun main(args: Array) {


    runApplication(*args) {


    this.addInitializers(beans)


    }


    }


    val beans = beans {


    bean {


    CommandLineRunner {


    println("start data initialization
    .. .
    ")


    val repository = ref()


    repository.save(Message(text = "this is the first message!"))


    repository.save(Message(text = "this is the second


    }


    }


    }

    View full-size slide

  81. Trailing lambdas + (extension) functions +


    named parameters + lambda w/ receiver = DSL
    fun foo(f: ()
    ->
    Unit) {}


    fun bar(f: ()
    ->
    Unit) {}


    fun baz(f: ()
    ->
    Unit) {}


    fun blah(id: Int, f: Klazz.()
    ->
    Unit) {}


    class Klazz(var text: String)


    fun Klazz.hello() : String = "Hello"


    View full-size slide

  82. val person: Person? = getPerson()


    println(person.firstName)


    fun getPerson(): Person? {…}


    data class Person(


    var firstName: String,


    //



    )


    View full-size slide

  83. val person: Person? = getPerson()


    println(person.firstName)


    fun getPerson(): Person? {…}


    data class Person(


    var firstName: String,


    //



    )


    Can return null

    View full-size slide

  84. val person: Person? = getPerson()


    println(person.firstName)


    fun getPerson(): Person? {…}


    data class Person(


    var firstName: String,


    //



    )


    Can be null

    View full-size slide

  85. val person: Person? = getPerson()


    println(person
    ?.
    firstName)


    fun getPerson(): Person? {…}


    data class Person(


    var firstName: String,


    //



    )


    Null-safe dereferencing

    View full-size slide

  86. val person: Person? = getPerson()


    println(person
    !!
    .firstName)


    fun getPerson(): Person? {…}


    data class Person(


    var firstName: String,


    //



    )


    “I know what I’m doing”

    View full-size slide

  87. Can be null
    Should not be null

    View full-size slide

  88. build.gradle.kts

    View full-size slide

  89. Kotlin features you have seen now
    Type inference


    Inline functions


    Data classes


    Rei
    fi
    ed generics


    Top-level functions


    Named arguments
    Operator overloading


    Trailing lambdas


    Extension functions


    Functional literal with receiver


    Nullable types


    Support for JSR-305

    View full-size slide

  90. 2.0 is coming soon!

    View full-size slide

  91. 2.0 is coming soon!
    An OSS framework
    Server & client apps
    Multiplatform

    View full-size slide

  92. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 8080) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    View full-size slide

  93. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 8080) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Start an embedded server with
    Netty engine on port 8080

    View full-size slide

  94. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 8080) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Other options:


    Tomcat, Jetty, CIO

    View full-size slide

  95. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 8080) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Fixed port

    View full-size slide

  96. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 0) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Random port

    View full-size slide

  97. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 0) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Adding routes

    View full-size slide

  98. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 0) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Request mapping

    View full-size slide

  99. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 0) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    Write response

    View full-size slide

  100. import io.ktor.server.engine.*


    import io.ktor.server.netty.*


    import io.ktor.application.*


    import io.ktor.response.*


    import io.ktor.routing.*


    fun main() {


    embeddedServer(Netty, port = 8080) {


    routing {


    get("/") {


    call.respondText("Hello World!")


    }


    }


    }.start(wait = true)


    }


    dependencies {


    implementation("io.ktor:ktor-server-core:$ktor_version")


    implementation("io.ktor:ktor-server-netty:$ktor_version")


    implementation("ch.qos.logback:logback-classic:$logback_version")


    testImplementation("io.ktor:ktor-server-tests:$ktor_version")


    testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlin_version")


    }
    build.gradle.kts:

    View full-size slide

  101. How can I do … with Ktor?

    View full-size slide

  102. How can I do … with Ktor?
    Persistence
    Logging
    Authentication
    Testing
    Serialization
    Monitoring
    Views

    View full-size slide

  103. How can I do … with Ktor?
    Logging
    Authentication
    Testing
    Serialization
    Monitoring
    JDBC / jdbi / Exposed / SQLDelight / jOOQ
    SLF4J, Logback, Log4j
    Jackson, Gson, kotlinx.serialization
    Views
    kotlinx.html, Velocity, Freemarker, Thymeleaf
    kotlin-test, JUnit,


    Testconainers
    Prometeus, OpenTracing
    Ktor *
    Persistence

    View full-size slide

  104. Framework Toolkit
    VS

    View full-size slide

  105. YouTube.com/kotlin

    View full-size slide

  106. https://speakerdeck.com/antonarhipov
    @antonarhipov
    https://youtube.com/kotlin

    View full-size slide