Slide 1

Slide 1 text

Microserviços em Kotlin com Dropwizard Felipe Lima Kotlin Meetup São Paulo 25 de Junho de 2020 felipecsl.com @felipecsl

Slide 2

Slide 2 text

Introdução

Slide 3

Slide 3 text

Um pouco de história…

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Dropwizard

Slide 7

Slide 7 text

Dropwizard @ Airbnb

Slide 8

Slide 8 text

Fonte: website oficial - dropwizard.io “Dropwizard is a Java framework for developing ops-friendly, high- performance, RESTful web services.”

Slide 9

Slide 9 text

“Elefante na sala"

Slide 10

Slide 10 text

“Tá, mas por que diabos eu deveria usar Dropwizard ao invés de ”

Slide 11

Slide 11 text

Fonte: https://blog.overops.com/java-bootstrap-dropwizard-vs-spring-boot Dropwizard vs. Spring Boot

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Meu favorito

Slide 14

Slide 14 text

• Criado em 2011 no Yammer • Arquitetura modular • Foco em produtividade, “get things done” • Java centric • Utiliza Jersey e Jetty Características

Slide 15

Slide 15 text

Modularidade https://modules.dropwizard.io/official/

Slide 16

Slide 16 text

Simplicidade companion object { @Throws(Exception::class) @JvmStatic fun main(args: Array) { BrokerApplication().run(*args) } }

Slide 17

Slide 17 text

Simplicidade class BrokerApplication : Application() { override fun initialize(bootstrap: Bootstrap) { bootstrap.apply { addBundle(webSocketBundle) addBundle(SslReloadBundle()) addBundle(RedirectBundle(HttpsRedirect())) } } override fun run(configuration: BrokerConfiguration, environment: Environment) { userDao = DaoFactory(environment, configuration).newDao(UserDao::class.java) sessionManager = SessionManagerFactory.newInstance( userDao, objectMapper, configuration ) environment.jersey().register(StatusResource(sessionManager)) environment.healthChecks().register("template", BrokerHealthCheck()) environment.jersey().register(UsersResource(userDao, sessionManager)) }

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

REST "Eclipse Jersey is a REST framework that provides a JAX-RS (JSR-370) implementation” https://eclipse-ee4j.github.io/jersey/

Slide 20

Slide 20 text

REST https://github.com/jax-rs/spec/blob/master/spec.pdf

Slide 21

Slide 21 text

REST @Path("/status") @Produces(MediaType.APPLICATION_JSON) class StatusResource(private val sessionManager: SessionManager) { @GET @Timed fun healthStatus(): HealthStatus { return HealthStatus(sessionManager.totalActiveSessions()) } }

Slide 22

Slide 22 text

REST @Path("/users") @Produces(MediaType.APPLICATION_JSON) class UsersResource( private val userDao: UserDao, private val sessionManager: SessionManager ) { @POST @Timed @Consumes(MediaType.APPLICATION_JSON) fun create(user: User): Response { userDao.insert(user) return Response.ok().build() } @PUT @Timed @Consumes(MediaType.APPLICATION_JSON) fun update(user: User): Response { userDao.updateUserIdByFcmToken(user) return Response.ok().build() } }

Slide 23

Slide 23 text

Configurações • Único arquivo YAML • Passado por parâmetro para o server via linha de comando • Pode ser utilizado para centralizar todas as configurações do servidor

Slide 24

Slide 24 text

Configurações // build.gradle run { args 'server', 'src/dist/config/broker.dev.yml' }

Slide 25

Slide 25 text

Configurações database: driverClass: org.postgresql.Driver user: felipecsl password: url: jdbc:postgresql://localhost/clairvoyance_dev properties: charSet: UTF-8 # the maximum amount of time to wait on an empty pool before throwing an exception maxWaitForConnection: 1s # the SQL query to run when validating a connection's liveness validationQuery: "/* MyService Health Check */ SELECT 1" # the minimum number of connections to keep open minSize: 8 logValidationErrors: true # the maximum number of connections to keep open maxSize: 32 # whether or not idle connections should be validated checkConnectionWhileIdle: false # the amount of time to sleep between runs of the idle connection validation, abandoned cleaner and idle pool resizing evictionInterval: 10s # the minimum amount of time an connection must sit idle in the pool before it is eligible for eviction minIdleTime: 1 minute server: applicationContextPath: / applicationConnectors: - type: http port: 8080

Slide 26

Slide 26 text

Configurações class BrokerApplication : Application() { // ... }

Slide 27

Slide 27 text

Configurações class BrokerConfiguration : Configuration() { @JsonProperty var fcmCredentialJsonPath: String? = null @JsonProperty var iceConfigFilePath: String? = null @JsonProperty var database: DataSourceFactory = DataSourceFactory() }

Slide 28

Slide 28 text

Database implementation "io.dropwizard:dropwizard-jdbi3:$dropwizardVersion"

Slide 29

Slide 29 text

Database @RegisterRowMapper(UserMapper::class) interface UserDao { @SqlQuery("SELECT * FROM users") fun all(): List @SqlQuery("SELECT * FROM users WHERE user_id = :user_id") fun findByUserId(@Bind("user_id") userId: String): User? @SqlUpdate("UPDATE users SET user_id = :user_id, fcm_token = :fcm_token WHERE ID = :id") fun updateById(@BindBean user: User): Int @SqlUpdate("INSERT INTO users (user_id, fcm_token) VALUES (:user_id, :fcm_token)") fun insert(@BindBean user: User): Int @SqlUpdate("DELETE FROM users") fun deleteAll(): Int }

Slide 30

Slide 30 text

Database Migrations // build.gradle plugins { id "org.flywaydb.flyway" version "6.4.0" } flyway { url = 'jdbc:h2:file:./clairvoyance_test' user = ‘fulano_de_tal’ }

Slide 31

Slide 31 text

Database Migrations private fun initFlyway(configuration: BrokerConfiguration) { val database = configuration.database Flyway.configure() .dataSource(database.url, database.user, database.password) .load() .migrate() }

Slide 32

Slide 32 text

Database Migrations

Slide 33

Slide 33 text

Frontend • Freemarker • Mustache

Slide 34

Slide 34 text

Testing testImplementation "io.dropwizard:dropwizard-testing:$dropwizardVersion"

Slide 35

Slide 35 text

Testing @ExtendWith(DropwizardExtensionsSupport::class) class BrokerApplicationTest { private val client = OkHttpClient.Builder().build() private val localPort = DROPWIZARD.localPort @Test fun status() { val client = JerseyClientBuilder().build() val result = client .target(“http://localhost:$localPort/status") .request() .get(String::class.java) assertThat(result).isEqualTo("""{"activeSessions":0}""") } companion object { private val DROPWIZARD = DropwizardAppExtension( BrokerApplication::class.java, ResourceHelpers.resourceFilePath("broker.yml") ) } }

Slide 36

Slide 36 text

Perguntas?

Slide 37

Slide 37 text

Obrigado!