Lately there’s been a lot of hype and buzz over micro services. The funny thing is, there’s absolutely nothing new about micro services. In fact, back in the good old days when I was trying to convince people that SOA was the way to go, if you designed a service bus the way you were supposed to, you ended up with micro services.

What is new, however, is the technology for creating, deploying, and managing micro services. Today we’ve got Docker, we have mesosphere, marathon, AWS, countless cloud providers, and Typesafe has even given us ConductR.

A microservice is, as its name implies, a very small service. This doesn’t mean that a micro service will have very few lines of code – it means that it should be singular in purpose. Think of a micro service as a service endpoint embodying the Single Responsibility Principle (SRP) that we all love from standard Object-Oriented Design.

To create a micro service you basically need three things:

  • HTTP Server (typically bootstrapped by the application)
  • Route Management (e.g. the REST resource definitions)
  • JSON serialization and de-serialization (although there’s nothing preventing you from using XML if you want)

For the first, we get a truckload of functionality by using Akka HTTP. I haven’t really started delving too much into this (for many reasons, not the least of which is that the documentation is literally littered with fragments that say “todo”), but it looks really powerful. The whole concept of flows and flow management of HTTP interaction sitting atop Akka streams seems like it could dramatically simplify the lives of developers who write services or HTTP clients (or in many cases, services that are also HTTP clients of other services).

For the second, Akka HTTP also provides built-in functionality that lets you bind routing definitions to an HTTP server. In classic Scala fashion, they’ve decided to use pattern matching and “combinator” syntax to let you define your routes.

Here’s a sample snippet where I’ve defined routes that expose GET resources for querying a single zombie or getting the complete list of all zombies in the zombie micro service:

val routes = {
 logRequestResult("zombies-microservice") {
   pathPrefix("zombies") {
     (get & path(Segment)) { zombieId =>
       complete {
         Seq(Zombie(zombieId, 12))
       }
     } ~
     (get) {
       complete {
         Seq(Zombie("bob", 1), Zombie("alfred", 2))
       }
     }
   }
}

You can probably infer from the little sample above how to use the pattern matching, parser combinator syntax to build robust, powerful route definitions. Syntax like “get & path(Segment)” is pretty straightforward – it defines a response to a GET on the resource and extracts out the segment as a lambda parameter, which we then use in the “complete { }” section below (complete indicates a completion of an HTTP server response future).

So now that we have our routes, we can start up an HTTP server using those routes:

object ZombieAkkaHttpMicroservice extends App with Service {
 override implicit val system = ActorSystem()
 override implicit val executor = system.dispatcher
 override implicit val materializer = ActorFlowMaterializer()

 override val config = ConfigFactory.load()
 override val logger = Logging(system, getClass)

 Http().bindAndHandle(routes,
     config.getString("http.interface"), config.getInt("http.port"))
}

The third piece of plumbing that makes this all work is the use of JSON serializers and de-serializers. In my sample, which is extrapolated from an Activator template, I use Spray JSON formatters. I find these a little disappointing, as the “JSON inception” macros you get with Play Framework work almost as if by magic, whereas the Spray formatters require you to tell spray the number of properties that are contained in the case class for which you’re creating a round-trip JSON formatter:

case class Zombie(name: String, speed: Int)

trait Protocols extends DefaultJsonProtocol {
 implicit val zombieFormat = jsonFormat2(Zombie.apply)
}

With those three pieces of the “bootstrap” in place (HTTP server, JSON serialization, REST API/routes definition) you have all the building blocks of a micro service that can be run standalone, or can be bundled and deployed as part of a Docker infrastructure, or deployed and managed using Typesafe’s newest product: ConductR.

With my app running (you can see nearly identical samples in the Activator template library), I can hit the local zombie micro service like so:

curl http://localhost:9001/zombies  (returns all zombies)
curl http://localhost:9001/zombies/spongebob (returns the zombie with ID spongebob)

Regardless of where you sit on the fence of opinion of micro services, it’s good to know that frameworks like Akka and their new (extremely appealing) HTTP libraries are at your disposal and you don’t have to resort to relying on bloated, bulky container models to get the job done.