Scala Quick Start – Developing a microservice with Dropwizard

You can make your Dropwizard microservices even more micro if you switch to Scala

There are many reasons why you might want to combine Dropwizard’s particular combination of Java web application technologies with the Scala programming language. These range from the utilitarian (leveraging a maturing and complete framework to do the heavy lifting) through the pragmatic (deployment consistency in an environment already heavily using Dropwizard services) through to the idiocy-appeasing (your design leads specify that your microservices may not exceed 2000 code lines and you want to pack more action in).

There are many approaches you could take too, such as leaning on Java for the boilerplate and delegating to your Scala code for the meaty bits, or leveraging the dropwizard-scala package to keep things simple.

Ingredients

My reasons are somewhat less straightforward and my approach here is to use the plain Java Dropwizard framework with just Scala code.

By way of an example I’m going to create a simple-as-possible HTTP service which accepts a password and verifies it against a password policy, returning OK if the checks pass, or an informative description of the password policy if the checks fail.

The ingredients for this quick start are almost as short as the code we’re going to put together (the final version of which is available on GitHub):-

Build file

Our list of ingredients is so short because sbt will take care of pulling down the Scala and Dropwizard requirements and Dropwizard will pull down everything else that it needs. So, in my passwordValidator root directory I’m going to kick off with a build.sbt which looks like this:-

name := "passwordValidator"
version := "1.0.0"
scalaVersion := "2.11.8"

libraryDependencies += "io.dropwizard" % "dropwizard-core" % "1.0.5"

Service configuration

We’re going to provide a couple of configurable properties for our deployed service; a regular expression to validate passwords against and some help-text to describe the current policy when validation fails. We’ll stick these properties in etc/passwordValidator.yaml:-

rule: ^(?=.*[a-z])(?=.*[A-Z])(?!.*\\s).{6,}$
help: Password must be at least six characters with at least 
             one upper-case and one lower-case character

We therefore need to extend io.dropwizard.Configuration with our two properties, a POJO scenario that Scala handles wonderfully concisely. Kicking off our src/main/scala/PasswordValidatorApplication.scala with:-

import com.fasterxml.jackson.annotation.JsonProperty
import io.dropwizard.Configuration

class PasswordValidatorConfiguration extends Configuration {
  @JsonProperty var rule : String = _
  @JsonProperty var help : String = _
}

Service Resource

Next up we need a Jersey resource which will implement our HTTP service endpoint (I’m carefully avoiding the word Restful here as there’s nothing very Restful about my example API!). Adding to our PasswordValidatorApplication.scala file:-

import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.QueryParam

…

@Path("/validatePassword")
class PasswordValidatorResource(rule: String, help: String) {
  @GET def validate(@QueryParam("password") password: String) : String = {
    if(password.matches(rule)) 
      "OK" 
    else 
      help
  }
}

Our PasswordValidatorResource accepts the regular expression rule and the help text in its constructor, and implements a single GET endpoint on /validatePassword which accepts a password to check as a parameter (e.g. /validatePassword?password=abcd1234.

Our implementation simply checks the provided password against the regular expression rule and returns either OK or the help-text depending on whether it matches or not.

Service Application

Finally we need to provide a little bit of Dropwizard glue to spin up our application and register our Jersey resource. Finishing our PasswordValidatorApplcation.scala file with:-

import io.dropwizard.Application
import io.dropwizard.setup.Environment

…

class PasswordValidatorApplication extends 
        Application[PasswordValidatorConfiguration] {
  def run(configuration: PasswordValidatorConfiguration, 
          environment: Environment) : Unit = {
    environment.jersey().register(new PasswordValidatorResource(
        configuration.rule, configuration.help))
  }
}

object PasswordValidatorApplication {
  def main(args: Array[String]) {
    new PasswordValidatorApplication().run(args:_*)
  }
}

Our PasswordValidatorApplication class just has a run method which constructs and registers our Jersey resource with the required configurable properties. The companion PasswordValidatorApplication object provides our main entry point which creates an instance of the class and calls run to kick things off.

Job done. We can now run our service with sbt:-

$ sbt "run server etc/passwordValidator.yaml"

And test it with curl:-

$ curl "http://localhost:8080/validatePassword?password=invalid"
Password must be at least six characters with at least one upper-case 
and one lower-case character

$ curl "http://localhost:8080/validatePassword?password=IAmValid"
OK

Deployment

We can follow the Dropwizard deployment recommendations and create a “fat jar” for our microservice with the help of the sbt-assembly plugin.

Creating project/plugins.sbt as:-

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")

All we then need to do is to run the following command:-

$ sbt assembly

And we’ve got a single, deployable JAR we can spin-up in the normal way:-

$ java -jar ./target/scala-2.11/passwordValidator-assembly-1.0.0.jar 
        server etc/passwordValidator.yaml

Next steps

This is obviously about as screamingly lightweight a microservice example as it is possible to conceive. In addition to metrics and healthchecks, in a real world scenario we’d almost certainly want to formalise our API input and output with some sort of JSON structure, validate our input and handle errors appropriately. Oh, and a few tests would be nice! But this is, after all, just a quick-start.

I am going to revisit this example in my next post though to look at more complex service configuration scenarios and how we can make Dropwizard a little more Scala friendly.

Leave a Reply

Your email address will not be published. Required fields are marked *