komparing kotlin server frameworks - jetbrains...1. backends are what apps/clients talk to so that...

45
Komparing Kotlin Server Frameworks Ken Yee @KAYAK (Android and occasional backend developer) KotlinConf 2018

Upload: others

Post on 05-Jan-2020

22 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Komparing Kotlin Server Frameworks

Ken Yee @KAYAK(Android and occasional backend developer)KotlinConf 2018

Page 2: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Agenda- What is a backend?- What to look for in a server framework?- What Kotlin frameworks are available?- Pros/Cons of each framework- Avoiding framework dependencies- Serverless

Page 3: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

What is a Backend? REST APIWeb serverChat server

Page 4: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

1. Backends areWhat apps/clients talk to so that users can

➔ Read dynamic dataSo you can share information

➔ AuthenticateBecause it’s about user access

➔ Write persistent dataTo save user interactions

Page 5: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

2. Backends mustBe reliable

➔ Read dynamic dataScalable from user load

➔ AuthenticateSecure from hacking

➔ Write persistent dataResilient to server failures

Page 6: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

What do you look for in a framework? Kotlin, DSL, Websockets, HTTP/2, Non-Blocking, CORS, CSRF, OIDC, OAuth2, Testing, Documentation

Page 7: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

1. Kotlin!On the server is:

➔ Isomorphic LanguageWith Kotlin clients

➔ Concise and ModernExtension and Higher Order functions, DSLs, Coroutines

➔ Null/Type SafeVersus Javascript, Python, Ruby

➔ Compatible w/ Java8Delay moving to Java 9/10/11

Page 8: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Java (Spring) Kotlin (Spring)class BlogRouter(private val blogHandler: BlogHandler) {

fun router() = router { ("/blog" and accept(TEXT_HTML)).nest { GET("/", blogHandler::findAllBlogs) GET("/{slug}", blogHandler::findOneBlog) }

("/api/blog" and accept(APPLICATION_JSON)).nest { GET("/", blogHandler::findAll) GET("/{id}", blogHandler::findOne) } }}

public class BlogRouter {public RouterFunction<ServerResponse>

route(BlogHandler blogHandler) {return RouterFunctions

.route(RequestPredicates.GET("/blog").and(RequestPredicates.accept(MediaType.TEXT_HTML)), blogHandler::findAllBlogs)

.route(RequestPredicates.GET("/blog/{slug}").and(RequestPredicates.accept(MediaType.TEXT_HTML)), blogHandler::findOneBlog)

.route(RequestPredicates.GET("/api/blog").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),blogHandler::findOne)

.route(RequestPredicates.GET("/api/blog/{id}").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), blogHandler::findOne);

}}

Page 9: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Express.js Kotlin (Spring)class BlogRouter(private val blogHandler: BlogHandler) {

fun router() = router { ("/blog" and accept(TEXT_HTML)).nest { GET("/", blogHandler::findAllBlogs) GET("/{slug}", blogHandler::findOneBlog) }

("/api/blog" and accept(APPLICATION_JSON)).nest { GET("/", blogHandler::findAll) GET("/{id}", blogHandler::findOne) } }}

var router = express.Router()var blogHandler = BlogHandler()

router.get('/blog', function (req, res) { res.send(blogHandler.findAllBlogs())})router.get('/blog/:slug', function (req, res) { res.send(blogHandler.findOneBlog(req))})

router.get('/api/blog', function (req, res) { res.send(blogHandler.findAll())})router.get('/blog/:id', function (req, res) { res.send(blogHandler.findOne(req))})

Page 10: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

2. SpeedEfficiency

➔ Non-blockingReactor/RxJava/Kotlin CoroutinesEvent driven w/ Netty vs. threading

➔ Http/2Formerly Google’s SPDY that uses single connections for multiple downloadsPush resources to clients

➔ WebsocketsUseful for real-time chat/games

Page 11: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

3. CORS (web)Cross Origin Resource Sharing

➔ Browser securityAllows browsers to access different domains for static files (images, CSS, JS, HTML, etc.)

➔ Javascript securityAllows web clients to use different hosts for APIs

Page 12: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

4. CSRF (web)Cross Site Request Forgery

➔ Browser form securityPrevents other sites from sending in the same form fields for a request

➔ Javascript API call securityPrevent AJAX calls from being run from malicious sites

Page 13: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

5. OAuth2/OIDCDelegation vs. Authentication

➔ Oauth2Standard refresh tokens and access token that can be revokedOnly for delegation

➔ OIDCOpenID Connect; aka, OAuth2 v2 or OpenID v3User verificationJSON Web Token encoded dataAuth token and delegation tokenKeycloak, Hydra, Okta, Auth0

Page 14: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

6. TestingBug prevention

➔ Unit TestingTest internal business logic

➔ Integration TestingTest server integration

Page 15: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

7. DocumentationHow, Help

➔ Official DocumentationClear documentation for featuresUseful examples

➔ CommunityStackOverflowGithub starsReal projects

➔ APISwagger/RAML

Page 16: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Which frameworks?

Ktor, Http4KJoobyVert.xSpring, ...

Page 17: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Features

Age

Javalin

SparkJava

Ktor

JoobyVert.x

Spring

Http4K

Ratpack

Frameworks

Micronaut

Page 18: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Ktor Ktor Routingrouting { accept(ContentType.Text.Html) { get(“/blog”) { call.respond(blogHandler::findAllBlogs) } get(“/blog/{slug}”) {call.respond(blogHandler::findOneBlog) } }

accept(ContentType.Application.Json) { get("/api/blog") { call.respond(blogHandler::findAll) } get("/api/blog/{id}") {call.respond(blogHandler::findOne) } }}

➔ ProsJetBrains’ official server frameworkPure KotlinGoal of Kotlin/Native supportKotlin coroutine supportWebsocketsUses Netty for async engineIncludes Multi-platform clientOauth support for Google/Twitter/FB

➔ ConsLeast mature pure-Kotlin frameworkNot much module support but enoughOnly Freemarker/Velocity templatesNo opentracing/micrometer support

Page 19: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Ktor Coroutinesget("/{...}") {

withContext(CommonPool) {

call.slow()

}

}

private suspend fun ApplicationCall.slow() { respondHtml { body { "Slow result" } }}

Page 20: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Web

API

DB

Load Balancers

Clients

Monolith Architecture

Page 21: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Web

AccountLoad

Balancers/Service Locators

Clients

Cart

Logging (ELK)

GatewayMicroservice Architecture

Tracing (Zipkin)

Page 22: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Service Mesh➔ Massively Distributed

➔ Self-Healing

➔ Self-Scaling

➔ Debugging is hard

➔ Logging is hard

➔ Perf monitoring is hard

Paradigma Digital

Page 23: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Http4K Http4K Routingroutes( “/blog” bind routes( “/” bind GET to { _ -> bloghandler.findAllBlogs() }, “/{slug}” bind GET to { req -> bloghandler.findOneBlog(req) } ), “/api” bind routes( “/blog” bind GET to { _ -> bloghandler.findAll() }, “/blog/{id}” bind GET to { req -> bloghandler.findOne(req) } )).asServer(Jetty(8000)).start()

➔ ProsPure KotlinNo magic reflection/annotationsResilience4J supportPluggable backends (Netty/Undertow)Micrometer supportSwagger supportOAuth support for Auth0 and GoogleCan deploy to AWS LambdaGraalVM supportChaos testing

➔ ConsNo Kotlin coroutine supportNo Opentracing but has ZipkinNo auto JSON encode/decode

Page 24: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Jooby Jooby Routingclass App: Kooby({ use(Jackson())

get("/blog") { bloghandler.findAllBlogs() } get("/blog/:slug") { req -> bloghandler.findOneBlog(req.param(“slug”).value) }

get("/api/blog") { bloghandler.findAll() } get(“/api/blog/:id”) { blogHandler.findOne(req.param<Int>(“id”)) }})

➔ ProsPluggable backendsEvent loop non-blockingRxJava/ReactorEven more modules than Http4KSwagger/RAMLLots of DB supportJob scheduling

➔ ConsNo Kotlin coroutine supportNo zipkin or opentracing support

Page 25: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Vert.x Vert.x Routingprivate val router = Router.router(vertx).apply { get("/blog") .handler(bloghandler::findAllBlogs) get("/blog/:slug") .handler(bloghandler::findOneBlog)

get("/api/blog") .handler(bloghandler::findAll) get("/api/blog/:id") .handler (bloghandler::findOne)}

➔ ProsKotlin coroutine supportEvent loop non-blockingNear top in TechEmpower benchmarksMicrometer and HawkularAuto-clusteringPolyglot (JS, Python, Clojure, Java, etc.)Redpipe for RxJavaKovert (convention vs. configuration)Swagger supportGraalVM support coming soon

➔ ConsA bit more monolith than microserviceNot very mainstream in USNo auto JSON encode/decode

Page 26: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Vert.x

Page 27: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Vert.x Kovertroute.bindController(BlogApiController, “/api”)

class BlogApiController(val blogHandler: BlogHandler = Injekt.get()) { public fun listBlog(): List<Blog> = blogHandler.findAll() public fun findBlogById(val id: String): Blog = { val blog = blogHandler.findOne(id) if (blog == null) throw HttpErrorNotFound() return blog}

Autogens:/api/blog - list of blogs/api/blog/:id - get blog with id

Page 28: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Spring Spring Routingclass BlogRouter(private val blogHandler: BlogHandler) {

fun router() = router { ("/blog" and accept(TEXT_HTML)).nest { GET("/", blogHandler::findAllBlogs) GET("/{slug}", blogHandler::findOneBlog) }

("/api/blog" and accept(APPLICATION_JSON)).nest { GET("/", blogHandler::findAll) GET("/{id}", blogHandler::findOne) } }}

➔ ProsMost popular frameworkWebflux/Reactor non-blockingKitchen sink can be dauntingSpring Initializer project autogenJHipsterSwagger supportGraalVM support in 5.2

➔ ConsNeed kotlin-spring/jpa pluginsNo official Kotlin coroutine support (see Kaminski’s coroutine library - Spring Fu)Slowest framework

Page 29: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Spring WebFlux @GetMapping("/api/blog/{id}") public Mono<ResponseEntity<Blog>> getBlogById(@PathVariable(value = "id") String blogId) { return Mono.fromCallable(blogHandler.findOne(blogId)) .map(blog -> ResponseEntity.ok(blog)) .defaultIfEmpty(ResponseEntity.notFound().build()); }

Page 30: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Spring Fu (incubator)fun routes(blogHandler: BlogHandler) = router { "/blog".nest { GET("/") { blogHandler::findAllBlogs } GET("/{id}") { blogHandler::findOneBlog } } "/api/blog".nest { GET("/", blogHandler::findAll) GET("/{id}", blogHandler::findOne) }}

Page 31: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

JHipster JHipster Cmdsjhipster --blueprint generator-jhipster-kotlinyo jhipster:import-jdl blog-jdl.jh

https://developer.okta.com/blog/2018/03/01/develop-microservices-jhipster-oauth

➔ ProsScaffolds Spring/Angular projectsNetflix OSS + Spring BootCan generate Kotlin projectsDesign data models and autogen CRUDRAILS/GRAILS-likeGenerates Netflix microservice archIncludes user management (UAA)

➔ ConsHarder to find where to change thingsEasy to complicate simple projects

Page 32: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s
Page 33: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

zipkin

Page 34: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Similarity?DSL

Request headers/params

Response output

Context

Page 35: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Code Portability

➔ Isolate Framework APIsBusiness logic -> framework API

➔ Isolate Business LogicBusiness logic -> API facades

➔ Isolate Database AccessJooq or other DB layer

➔ Coroutines or RxJavakotlinx-coroutines-rx2

Page 36: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

API Facades

➔ Logging FacadeSlf4j

➔ Tracing FacadeOpentracing, OpenCensus

➔ Metrics FacadeMicrometer, OpenCensus, DW

Page 37: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Serverless?Google Cloud Functions

AWS Lambda

OpenFAAS

Azure Functions

Page 38: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

JVM Limitations

➔ Slow Startup

➔ Memory Usage

➔ Disk Size

Page 39: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

How bad is it?Compared to node.js

➔ 2-3x slower startup

➔ 1.5-2x memory

➔ 5-10x disk spaceIncluding JS libs

➔ 2x cost on Amazon Lambda

https://www.bouvet.no/bouvet-deler/comparing-java-and-node.js-on-aws-lambda

Page 40: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Kotlin vs. Go

➔ 2-3x slower startup

➔ 3x memory

➔ 2x disk space

➔ 8x cost on Amazon Lambda

https://blog.travelex.io/blazing-fast-microservice-with-go-and-lambda-d30d95290f28

Page 41: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

But There’s Hope

➔ GraalVM (SubstrateVM)Http4k, Vert.x, Spring 5.2

➔ Kotlin/NativeKtor

Page 42: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

LimitationsGraalVM

➔ No Dynamic Class Loading

➔ No JMX VM monitoring

➔ Vert.x 3x less memoryHttp4k 4x less memory

➔ Vert.x 9x faster startupHttp4k 50x faster startup

https://vertx.io/blog/eclipse-vert-x-goes-native/https://www.richyhbm.co.uk/posts/compiling-kotlin-netty-webapp-with-graalvm/

Page 43: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

All The Things!

Backends are easy in Kotlin

Lots of choices

Choose the features you need

Keep your business code portable

Page 44: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

Further Reading- https://nordicapis.com/api-security-oauth-openid-connect-depth/- https://ktor.io/- https://www.http4k.org/- https://jooby.org/- https://micronaut.io/- https://vertx.io/

- https://github.com/kohesive/kovert- http://redpipe.net/

- https://spring.io/- https://github.com/konrad-kaminski/spring-kotlin-coroutine

- https://www.jhipster.tech/- https://github.com/jhipster/jhipster-kotlin

- https://www.techempower.com/benchmarks/

Page 45: Komparing Kotlin Server Frameworks - JetBrains...1. Backends are What apps/clients talk to so that users can Read dynamic data So you can share information Authenticate Because it’s

KotlinConf Server Sessions- Kotlin and Spring Boot- Server as a Function (Http4K)- Full Stack Kotlin on Google Cloud- Building Server Backends with Ktor- Painless Microservices with Kotlin- GraphQL powered by Kotlin