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

Server-Side Kotlin by Ktor

kaonash
August 24, 2019

Server-Side Kotlin by Ktor

kaonash

August 24, 2019
Tweet

More Decks by kaonash

Other Decks in Programming

Transcript

  1. ɹɹɹɹ
    Server-Side Kotlin By
    UPSIDERɹਗ਼ਫݦ

    View Slide

  2. SELF INTRODUCTION
    • ਗ਼ਫݦ(@kaonash_)
    • Lead Software Engineer @ UPSIDER
    • Ҡॅ͍ͨ͠ܥΤϯδχΞʢ2022೥ɺ௕໺ʹҠॅ༧ఆʣ
    • Love: ୌ / Kitkat / Kotlin

    View Slide

  3. SELF INTRODUCTION
    UZABASEɿاۀɾۀք෼ੳϓϥοτϑΥʔϜͷ։ൃɻServer-side Javaɻ

    NewsPicksʢࣾ಺స੶ʣɿܦࡁχϡʔεΞϓϦͷ։ൃɻServer-side͸JavaɺAndroidΞϓϦ։ൃ
    ͰKotlinॳମݧɻ

    Bizreachɿ৽نࣄۀͱͯ͠ैۀһσʔλϕʔεαʔϏεͷ։ൃɻServer-side Kotlin(Spring Boot)

    UPSIDERɿ૑ۀҰ೥ͷελʔτΞοϓʹͯB to BͷFinTechϓϩμΫτΛ։ൃɻServer-side
    Kotlin(Ktor)

    View Slide

  4. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  5. ࠓ೔࿩͞ͳ͍͜ͱ
    • Ktorͷৄ͍͠࢓૊Έ
    • ຊ൪ӡ༻ͯ͠Έͨײ૝ʢ·ͩϦϦʔεલͳͷͰɾɾɾʣ

    View Slide

  6. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  7. Server-Side Kotlinͬͯ࢖͑Δͷʁ
    ɾJavaΛ࠾༻ͨ͠έʔεͱൺ΂ͯ΋શવҧ࿨ײͳ͍
    ɹɹɹͱ͍͏͔ਖ਼௚ɺҰ౓Kotlinʹ׳ΕͪΌ͏ͱ΋͏JavaͰॻ͖ͨ͘ͳ͘ͳΔ
    ɾܕਪ࿦΍֦ுؔ਺ͳͲͷ͓͔͛ͰඇৗʹεοΩϦ͔͚Δ
    ɾnull-safety࠷ߴ
    ɾJava੡ͷϥΠϒϥϦ͕࢖͑ΔͨΊɺΤίγεςϜʹ͍ͭͯ΋৺഑ෆཁ
    ɾͨͩ͠ɺJava੡ϥΠϒϥϦར༻࣌ʹ͸མͱ͕݀͠ɾɾɾ

    View Slide

  8. Java੡ϥΠϒϥϦར༻࣌ͷ஫ҙ఺
    ɾJavaͷϝιουΛݺͼग़͢ͱɺ໭Γ஋͸T!ܕ
    (=T΋͘͠͸T?)ʹͳΔ
    ɾϥΠϒϥϦଆͰରԠͯ͠ͳ͍ͱnull-safetyͷੈք͕յΕΔ
    val message = "test"
    val encrypted = StringEncrypter.encrypt(message) // StringEncrypter͕JavaϥΠϒϥϦͩͱ
    println(encrypted.length) // ͜͜Ͱ͵ΔΆʹͳΔ͔΋

    View Slide

  9. ʮ͔ͤͬ͘Kotlinʹͨ͠ͷʹɾɾɾʯ
    ײ͸ਖ਼௚ͪΐͬͱ͋Δ

    View Slide

  10. Kotlin੡ϥΠϒϥϦͳΒ҆৺ʂ

    View Slide

  11. Ͱ΋Server-sideͰ࢖͑ΔΑ͏ͳ
    Kotlin੡ͷϥΠϒϥϦͳΜͯɾɾɾ

    View Slide

  12. ࠓΊͬͪΌ૿͑ͯ·͢ʂ

    View Slide

  13. • Language : Kotlin
    • WebϑϨʔϜϫʔΫ : Ktor server
    • O/R Mapper : Exposed
    • DI : Koin
    • Http client : Ktor client
    • JSON Parser : Jackson
    • Testing : JUnit5 / AssertJ / MockK
    ฐࣾͷٕज़ελοΫ
    Server
    ΄΅Pure Kotlin!

    View Slide

  14. Server-side Kotlin͸ʮͰ͖Δʁʯ͔Β
    ʮԿΛબ΂͹͍͍ʁʯʮͲ͏΍ͬͨΒ͍͍ʁʯ΁

    View Slide

  15. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  16. WHAT IS
    • JetBrains͕։ൃͨܰ͠ྔɾඇಉظWebϑϨʔϜϫʔΫ
    • ಡΈํ͸ʮ͚͍ͨʔʯʢ࠷ॳ͸ʮͨ͜ʔʯͩͱࢥͬͯͨʣ
    • Pure Kotlin
    • PluggableʹඞཁͳػೳͷΈΛ௥Ճ͍͚ͯ͠Δ
    • 2018೥11݄ʹ1.0͕ϦϦʔεʂʢݱࡏͷ࠷৽͸1.2.3ʣ
    • Server͚ͩ͡Όͳͯ͘Client΋͋Δ
    https://ktor.io/clients/index.html

    View Slide

  17. Spring Bootͱͷ˒ͷࠩ
    ·ͩ·ͩ͜Ε͔Β͚ͩͲɺ͍ͩͿ஫໨͕ू·͖ͬͯͯΔ

    View Slide

  18. ͳͥKtorΛબΜͩͷ͔ʁ

    View Slide

  19. ٕज़બఆΛͨ͠λΠϛϯάɿ2018೥9݄

    View Slide

  20. ީิ
    • SpringBoot
    • Jooby
    • Ktor

    View Slide

  21. SpringBoot
    • ͍Θͣͱ஌ΕͨJavaքͷσϑΝΫτελϯμʔυɻServer-side KotlinͰ΋࠾༻ࣄྫ͕ଟ͘ଘࡏɻ
    • KotlinରԠ
    • લ৬ʢ౰࣌͸μϒϧϫʔΫͩͬͨͷͰݱ৬ʣ΋SpringBootͰServer-Side Kotlin΍ͬͯͨͷͰܦݧ͸͋
    Δ
    • શ෦ೖΓͰศརͳͷ͕ͩͦͷ෼ىಈ͕࣌ؒ௕͘ɺͦͷؒʹTwitterͱ͔Twitterͱ͔Twitterͱ͔Λݟͨ
    Γͯ͠͠·͏
    • Ξϊςʔγϣϯ஍ࠈ͕͋·Γ޷͖ʹͳΕͳ͍ɻɻɻʢݸਓͷײ૝Ͱ͢ʣ
    • ΫϦʔϯΞʔΩςΫνϟΛݕ౼͍ͯͨͨ͠Ίɺશମ͕ΨοπϦSpringʹґଘ͢Δͷ͕ͪΐͬͱ໰୊

    View Slide

  22. ࣮ࡍͷΞʔΩςΫνϟ
    ΫϦʔϯΞʔΩςΫνϟͷߟ͑Ͱ͸WebϑϨʔϜϫʔΫ͸ʮৄࡉʯͰ͋ΓϏδωεϩ
    δοΫ͔Β੾Γ཭͢΂͖΋ͷɻ
    Ͱ΋SpringBootͩͱDI΍Β@transactional΍ΒͰશମ͕ΨοπϦSpringʹґଘͯ͠͠·͏ɻ

    View Slide

  23. Jooby
    • ܰྔߴ଎ɺPluggableͳJava੡ϚΠΫϩϑϨʔϜϫʔΫɻ
    ࢥ૝͕Ktorͱ͔ͳΓ͍ۙɻ
    • KotlinରԠ
    • ଞࣾͷ࠾༻ࣄྫ΋͋Δ
    • ࠷ॳ͸ୈҰީิͩͬͨ

    View Slide

  24. Ktor
    • ٕज़બఆ౰࣌ͷόʔδϣϯ͸0.9.5
    • JetBrains੡ͱ͍͏͜ͱͰɺࠓޙ΋ϝϯς͞ΕΔͩΖ͏ͱ͍͏҆৺ײ
    • GithubͷIssuesΛνΣοΫͯ͠Έ͕ͨɺServerଆͰ͸͋·Γେ͖ͳ໰୊͸࢒ͬͯͳ͞
    ͦ͏
    • ʮ0.9ͷ࣍͸1.0͡ΌͶʁʯˠ݁Ռతʹ͸౰ͨͬͯͨ
    • Jooby΋͍͍͕ɺͲ͏ͤͳΒPure KotlinͷϑϨʔϜϫʔΫΛ࢖ͬͯΈ͍ͨ
    • ʮૣΊʹ࠾༻͢Ε͹ɺٕज़తʹ஫໨ΛूΊͯ࠾༻ͱ͔Ͱ΋༗རͦ͏ʯͱ͍͏ଧࢉ

    View Slide

  25. ݁࿦
    ʮͳΜ͔Ktor࢖ͬͯΈ͍ͨʯ

    View Slide

  26. ࣮ࡍ࢖ͬͯΈͯͷײ૝
    • ىಈૣ͍ͷ࠷&ߴʢ.ktϑΝΠϧ͕300ݸ͘Β͍ͷঢ়ଶͰϏϧ
    υऴΘ͔ͬͯΒ1.5ඵ͘Β͍Ͱىಈ׬ྃʣ
    • ඞཁͳ΋ͷ͸Ұ௨Γἧ͍ͬͯΔ
    • ֦ுؔ਺ɾߴ֊ؔ਺͕;ΜͩΜʹ࢖ΘΕ͍ͯΔͷͰɺ׳Ε
    ͯͳ͍ਓ͸࠷ॳͪΐͬͱށ࿭͏͔΋ʁ
    • શମͱͯ͠͸ͱͯ΋ຬ଍

    View Slide

  27. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  28. ͳʹ͸ͱ΋͋ΕHello World

    View Slide

  29. Hello World!
    Ktor serverͷىಈํ๏͸͍͔ͭ͋͘Δ͕ɺҰ൪؆୯ͳํ๏
    fun main() {
    embeddedServer(Netty, 8080) {
    install(Routing) {
    get("/") {
    call.respondText("Hello World!")
    }
    }
    }.start()
    }

    View Slide

  30. Hello World!
    fun main() {
    embeddedServer(Netty, 8080) {
    install(Routing) {
    get("/") {
    call.respondText("Hello World!")
    }
    }
    }.start()
    }
    NettyΛར༻ͯ͠ΞϓϦέʔγϣϯΛ࡞੒
    port൪߸͸8080
    Get methodͰpath"/"͕ݺͼग़͞ΕͨΒ
    responseͱͯ͠"Hello World!"ͱ͍͏จࣈྻΛฦ٫͢Δ
    ͜ͷblockͰroutingΛఆٛ

    View Slide

  31. ΑΓॊೈͳىಈํ๏

    View Slide

  32. EngineMain

    View Slide

  33. EngineMain
    • EngineMain͸Ktor͕༻ҙͨ͠Ϋϥε
    • ར༻͢ΔEngineʹΑͬͯ4छྨ༻ҙ͞Ε͍ͯΔ
    • io.ktor.server.cio.EngineMain
    • io.ktor.server.tomcat.EngineMain
    • io.ktor.server.jetty.EngineMain
    • io.ktor.server.netty.EngineMain
    •mainؔ਺Λ͍࣋ͬͯΔͷͰɺαʔόʔىಈ࣌͸͜ͷϝιουΛ࣮ߦ
    •ىಈ࣌ʹࣗಈతʹapplication.confͱ͍͏ઃఆϑΝΠϧΛಡΈࠐΈɺͦͷઃఆ
    ಺༰ʹΑͬͯىಈ࣌ͷॲཧΛܾఆ

    View Slide

  34. EngineMain
    • ར༻͢Δػೳ͸ɺApplicationΫϥεͷ֦ுؔ਺ʹͯఆٛ͢Δ
    fun Application.module() {
    install(Routing) {
    get("/") {
    call.respondText("Hello World!")
    }
    }
    }
    Application.kt
    ͜ͷϝιου໊͸ͳΜͰ΋͍͍
    installϝιουΛ௥Ճ͍ͯ͘͜͠ͱͰɺඞཁͳػೳΛ޷͖ʹ૊ΈࠐΊΔ

    View Slide

  35. EngineMain
    • ઃఆϑΝΠϧapplication.confʹɺىಈͷઃఆ৘ใΛهड़
    ktor {
    deployment {
    port = 8080
    }
    application {
    modules = [ ApplicationKt.module ]
    }
    }
    application.conf
    (ύοέʔδ໊.)Ϋϥε໊(ϑΝΠϧ໊ͷ຤ඌʹKtΛ͚ͭΔ).֦ுؔ਺໊

    View Slide

  36. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  37. Routing
    • RoutingΛinstall͢Δ͜ͱͰɺrouteొ࿥͕Ͱ͖Δ
    • call.parameters͔ΒϦΫΤετύϥϝʔλ΍ύεύϥϝʔλ
    ΛऔಘՄೳʢͨͩ͠ܕ͸͢΂ͯStringʹͳΔʣ
    fun Application.module() {
    install(Routing) {
    get("/users/{userId}") {
    // ܕ͸ඞͣStringͳͷͰඞཁʹԠͯ͡Ωϟετ͢Δ
    val userId = call.parameters["userId"].toLong()
    }
    }
    }

    View Slide

  38. ΋ͬͱλΠϓηʔϑʹ
    ύϥϝʔλʔΛѻ͍͍ͨ

    View Slide

  39. Locations

    View Slide

  40. Locations(※ݱࡏ͸·ͩexperimental)
    • ύϥϝʔλΛλΠϓηʔϑʹѻ͑Δ
    • Int, Long, Float, Double, Boolean, String, enum͕࢖༻Մೳ
    @Location("/users/{userId}")
    data class UserLocation(val userId: Long)
    fun Application.module() {
    install(Locations)
    install(Routing) {
    get { param ->
    // param͸UserLocationܕʹͳΔͷͰɺuserIdΛͦͷ··LongܕͰऔಘͰ͖Δ
    val userId = param.userId
    }
    }
    }

    View Slide

  41. Locationͷωετ΋Ͱ͖Δ
    @Location("/users/{userId}")
    data class UserLocation(val userId: Long) {
    @Location("/email")
    data class EmailLocation(val userLocation: UserLocation)
    }
    • ؔ࿈ͨ͠routeΛ·ͱΊΒΕΔͷ͸ϝϦοτ͕ͩɺ਺͕૿͑ͯ͘
    Δͱͪ͝Όͪ͝Όͯ͠Θ͔ΓͮΒ͘ͳΔ
    • ʮKtorͷRoutingఆٛͷϕετϓϥΫςΟεΛߟ͑ͯΈΔʯʹৄ
    ͘͠ॻ͖·ͨ͠ʢͪͳΈʹલ৬ͷTechϒϩάʣ

    https://tech.bizreach.co.jp/posts/324/ktor-routing/

    View Slide

  42. ΋͏Ұาલ΁

    View Slide

  43. ϓϦϛςΟϒҎ֎ͷܕ΁ͷࣗಈม׵

    View Slide

  44. ͨͱ͑͹ValueObject
    • ͜Μͳײ͡ͰɺValueObject΋ࣗಈͰม׵Ͱ͖Δͱศར
    data class UserId(val userId: Long)
    @Location("/users/{userId}")
    data class UserLocation(val userId: UserId)
    fun Application.module() {
    install(Locations)
    install(Routing) {
    get { param ->
    val userId = param.userId // UserIdܕͰͦͷ··औಘͰ͖Δʂ
    }
    }
    }

    View Slide

  45. DataConversionΛ࢖͏ͱͰ͖·͢
    fun Application.module() {
    install(DataConversion) {
    convert {
    decode { values, _ ->
    values.singleOrNull()?.let { UserId(it.toLong()) }
    }
    encode { id ->
    when (id) {
    is UserId -> listOf(id.value.toString())
    else -> throw DataConversionException("Can not convert.")
    }
    }
    }
    }
    }

    View Slide

  46. ͿͬͪΌ͚ɺSpringBootͱൺ΂ͯͲ͏ʁ
    • ֤Controllerʹ͚ͭΔ@RequestMapping
    ΞϊςʔγϣϯʹrouteΛهࡌ͢Δํࣜ
    • ਺͕૿͑Δͱʮ͜ͷAPIɺͲ͜ͷ
    ControllerݺΜͰΔΜ͚ͩͬʯ͕୳ͮ͠
    Β͍໰୊
    SpringBoot Ktor
    • routeΛ·ͱΊͯఆٛ͢Δํࣜ
    • LocationsΛ࢖Θͳ͍ͱλΠϓηʔϑʹ
    ѻ͑ͳͯͭ͘ΒΈ
    • Locations͸ఆٛͷ࢓ํΛؾΛ͚ͭͳ͍
    ͱΊͬͪΌಡΈͮΒ͘ͳΔ
    Ұ௕Ұ୹ɻݸਓతʹ͸Ktorͷ΍Γํͷ΄͏͕޷͖͕ͩɺ
    Locationsͷ࢖͍উखΛ΋͏গ͠վળͯ͠΄͍͠

    View Slide

  47. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  48. ೝূॲཧ
    • ϕʔγοΫೝূ / Digestೝূ / JWT / LDAPೝূ / OAuthΛαϙʔτɻ
    • install(Authentication)͢Ε͹ར༻Մೳʢ௨ৗͷktorҎ֎ʹktor_authΛ
    dependenciesʹ௥Ճ͢Δ͜ͱ͕ඞཁʣ
    • Routingఆٛʹͯೝূ͕ඞཁͳrouteʹରͯ͠authenticate{}ϒϩοΫͰғΉͱɺ
    ೝূ͕௨͍ͬͯΔ৔߹͚ͩॲཧΛ࣮ߦ͢Δ͜ͱ͕Մೳɻ

    View Slide

  49. Routingଆ
    fun Application.module() {
    install(Routing) {
    // ͜͜͸ೝূෆཁ
    post(“/login") { // ϩάΠϯॲཧɻ੒ޭ࣌ʹ͸tokenΛੜ੒ͯ͠ฦ٫ }
    authenticate {
    // ͜ͷϒϩοΫ಺͸ೝূ͕௨ͬͯͳ͍ͱ࣮ߦͰ͖ͳ͍
    get("/users/{userId}") {
    // ͜ΕͰϩάΠϯϢʔβʔͷ৘ใΛऔಘͰ͖Δ
    val user = authentication.principal()!!
    ...
    }
    }
    }
    }

    View Slide

  50. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  51. DIʹ͍ͭͯ
    • DIࣗମ͸Ktorͷػೳͱͯ͠ఏڙ͞Ε͍ͯͳ͍ͷͰɺ޷͖ͳϥ
    ΠϒϥϦΛ࢖͍͍ͬͯ
    • KtorͷެࣜϖʔδʹKodeinΛ࢖ͬͨαϯϓϧ͕͋Δ
    • Koin͸ࣗલͰKtor༻ʹApplication.installͰ͖ΔFeatureΛఏڙ͠
    ͓ͯΓɺ͜ΕΛ࢖͏ͱKtorىಈ࣌ʹࣗಈͰDIίϯςφΛى
    ಈͯ͘͠ΕΔ

    View Slide

  52. KoinΛ࢖ͬͨྫ
    fun Application.module() {
    install(Koin) {
    modules(
    module {
    single { UserController() }
    }
    )
    }
    install(Routing) {
    val userController: UserController by inject()
    get("users") {
    call.respond(userController.find())
    }
    }
    }
    ͜ͷதͰDI͢ΔϞδϡʔϧΛఆ͓ٛͯ͘͠ͱ
    औಘॲཧΛinject()ʹҠৡ͢Δ͜ͱͰΦϒδΣΫτ͕औಘͰ͖Δʂ

    View Slide

  53. AGENDA
    • Server-Side Kotlinͷݱঢ়
    • ٕज़બఆͷϙΠϯτɿͳͥKtorΛબΜͩͷ͔ʁ
    • ࣮ફKtor
    • ىಈͷํ๏
    • Routing
    • ೝূ
    • DI
    • Testing

    View Slide

  54. TestEngine
    • Ktorʹ༻ҙ͞Ε͍ͯΔɺԾ૝తʹαʔόʔΛىಈ͢ΔͨΊͷςετ༻
    Engine
    • ىಈ࣌͸withTestApplication()Λ࢖༻͢Δ
    • ࣮ࡍͷHTTPϦΫΤετ͸ड͚෇͚ͳ͍͕ɺٙࣅϦΫΤετΛඈ͹͢͜ͱ
    ʹΑͬͯఆٛͨ͠routeΛݺͼग़͢͜ͱ͕Ͱ͖Δ

    View Slide

  55. TestEngineͷ࢖༻ྫ
    withTestApplication(Application::module) {
    handleRequest(HttpMethod.Post, "/login") {
    addHeader(HttpHeaders.ContentType,
    ContentType.Application.FormUrlEncoded.toString())
    setBody(listOf(
    "email" to "[email protected]",
    "password" to "loginPass"
    ).formUrlEncode())
    }.apply {
    assertThat(response.status()).isEqualTo(HttpStatusCode.OK)
    }
    }
    ىಈ͢ΔΞϓϦέʔγϣϯͷϝιουΛࢦఆ
    Httpϝιουͱpathͷࢦఆ
    HeaderͱBodyͷࢦఆ
    handleRequestͷ໭Γ஋TestApplicationCallܕ͕
    ϓϩύςΟͱͯ͠responseΛอ͍࣋ͯ͠Δ

    View Slide

  56. MockKͱKoinΛ࢖ͬͨMocking

    View Slide

  57. ͨͱ͑͹ɺ͜͏͍͏ॲཧΛ୯ମͰςετ͢Δʹ͸ʁ
    install(Routing) {
    val userController: UserController by inject()
    @Location("/users/{userId}")
    data class UserLocation(val userId: UserId)
    get {
    call.respond(userController.find(userId))
    }
    }
    ͍ͭ͜ΛMockԽ͍ͨ͠

    View Slide

  58. MockKͱKoin
    val userController = mockk(relaxed = true)
    val module = module { single { userController } }
    @Test
    fun `Return user data when called request with user id`() {
    val userId = UserId(1)
    every { userController.find(userId) } returns UserData(1, "ࢁాଠ࿠")
    withTestApplication(Application::module) {
    startKoin { modules(module) }
    handleRequest(HttpMethod.Get, "/users/1").apply {
    assertThat(response.status()).isEqualTo(HttpStatusCode.OK)

    }
    }
    }
    MockΦϒδΣΫτΛ࡞੒͠ɺKoinϞδϡʔϧʹొ࿥
    MockΦϒδΣΫτ͕ݺ͹Εͨ࣌ͷڍಈΛఆٛ
    KoinΛىಈ

    View Slide

  59. ׬ᘳɾɾɾͱࢥ͍͖΍

    View Slide

  60. ౖΒΕͨ

    View Slide

  61. ͳΜͰʁ
    • Application.moduleͰinstall(Koin)͢Δͱɺىಈ࣌ʹࣗಈతʹstartKoin͕ݺ͹ΕΔ
    fun Application.module() {
    install(Koin) {
    modules(
    module {
    single { UserController() }
    }
    )
    }
    }
    • TestEngineͰ΋Ծ૝తʹKtorΛىಈ͍ͯ͠ΔͨΊɺಉ͡Α͏ʹstartKoin͕૸Δ
    • MockΦϒδΣΫτΛΠϯδΣΫτ͢ΔͨΊʹstartKoin͢ΔͱೋॏىಈʹͳΔ

    View Slide

  62. ͱ͍͏͜ͱͰɺ1ߦ௥Ճ
    val userController = mockk(relaxed = true)
    val module = module { single { userController } }
    @Test
    fun `Return user data when called request with user id`() {
    val userId = UserId(1)
    every { userController.find(userId) } returns UserData(1, "ࢁాଠ࿠")
    withTestApplication(Application::module) {
    stopKoin()
    startKoin { modules(module) }
    handleRequest(HttpMethod.Get, "/users/1").apply {
    assertThat(response.status()).isEqualTo(HttpStatusCode.OK)

    }
    }
    }

    View Slide

  63. ࠶࣮ߦ

    View Slide

  64. Let’s enjoy Server-Side Kotlin and Ktor!!

    View Slide

  65. ࠷ޙʹએ఻

    View Slide

  66. WE ARE HIRING!!
    • Server side: Kotlin(Ktor)
    • Front: Nuxt.js, Typescript
    • Backend: Go
    • ࣄۀ಺༰ɿ๏ਓ޲͚VISAΧʔυΛ࢖ͬͨBtoBαʔϏεʢৄࡉ͸ۙ೔ެ։ʣ
    • ෭ۀ׻ܴ(Քಇि2ఔ౓ʙOKʣ
    • ϑϧϦϞʔτOKʢΦϑΟε͸࿡ຊ໦ʣ
    • ͪΐͬͱͰ΋ؾʹͳΔਓ͸࠙਌ձɺ΋͘͠͸Twitterʹͯ@kaonash_·Ͱʂ

    View Slide

  67. Thank you!!

    View Slide