Spray API Development: Getting Started with a Spray Web Service Using JSON

Spray is a great library for building http api’s with Scala. Just like Play! it’s built with Akka and provides numerous low and high level tools for http servers and clients. It puts Akka and Scala’s asynchronous programming model first for high performance, composable application development.

I wanted to highlight the spray-routing library which provides a nice DSL for defining web services. The routing library can be used with the standalone spray-can http server or in any servlet container.

We’ll highlight a simple entity endpoint, unmarshalling Json data into an object and deferring actual process to another Akka actor. To get started with your own spray-routing project, I created a giter8 template to bootstrap your app:

$g8 mhamrah/sbt -b spray

The documentation is quite good and the source code is worth browsing. For a richer routing example check out Spray’s own routing project which shows off http-streaming and a few other goodies.

Creating a Server

We are going to create three main structures: An actor which contains our Http Service, a trait which contains our route definition, and a Worker actor that will do the work of the request.

The service actor is launched in your application’s main method. Here we are using Scala’s App class to launch our server feeding in values from typesafe config:

Because Spray is based on Akka, we are just creating a standard actor system and passing our service to Akka’s new IO library. This is the high performance foundation for our service built on the spray-can server.

The Service Actor

Our service actor is pretty lightweight, as the functionality is deferred to our route definition in the HttpService trait. We only need to set the actorRefFactory and call runRoutes from our trait. You could simply set routes directly in this class, but the separation has its benefits, primarily for testing.

The Service Trait – Spray’s Routing DSL

Spray’s Routing DSL is where Spray really shines. It is similar to Sinatra inspired web frameworks like Scalatra, but relies on composable function elements so requests pass through a series of actions similar to Unfiltered. The result is an easy to read syntax for routing and the Dont-Repeat-Yourself of composable functions.

To start things off, we’ll create a simple get/post operation at the /entity path:

The path, get and complete operations are Directives, the building blocks of Spray routing. Directives take the current http request and process a particular action against it. The above snippet doesn’t much except filter the request on the current path and the http action. The path directive also lets you pull out path elements:

There are a number ways to pull out elements from a path. Spray’s unit tests are the best way to explore the possibilities.

You can use curl to test the service so far:

Unmarshalling

One of the nice things about Spray’s DSL is how function composition allows you to build up request handling. In this snippet we use json4s support to unmarshall the http request into a JObject:

We use the Entity to directive to unmarshall the request, which finds the implicit json4s serializer we specified earlier. SomeObject is set to the JObject produced, which is passed to our yet-to-be-built doCreate method. If Spray can’t unmarshall the entity an error is returned to the client.

Here’s a curl command that sets the http method to POST and applies the appropriate header and json body:

Leveraging Akka and Futures

We want to keep our route structure clean, so we defer actual work to another Akka worker. Because Spray is built with Akka this is pretty seamless. We need to create our ActorRef to send a message. We’ll also implement our doCreate function called within the earlier POST /entity directive:

There’s a couple of things going on here. Our worker class is looking for a Create message, which we send to the actor with the ask (?) pattern. The ask pattern lets us know the task completed so we call then tell the client. When we get the Ok message we simply return the result; in the case of an error we return a short message. The response future returned is passed to Spray’s complete directive, which will then complete the request to the client. There’s no blocking occurring in this snippet: we are just wiring up futures and functions.

Our worker doesn’t do much but out the message contents and return a random number:

You can view how the entire request is handled by viewing the source file.

Wrapping Up

Reading the documentation and exploring the unit tests are the best way to understand the power of Spray’s routing DSL. The performance of the standalone spray-can service is outstanding, and the Akka platform adds resiliency through its lifecycle management tools. Akka’s remoting feature allows systems to build out their app tiers. A project I’m working on is using Spray and Akka to publish messages to a pub/sub system for downstream request handling. It’s an excellent platform for high performance API development. Full spray-sample is on GitHub.

  • navadava

    Isn’t your WorkerActor synchronous? Note the ‘?’ you are using here.

  • kafecho

    The WorkerActor is not synchronous. The “?” (ask pattern) returns a Scala Future. When the Future completes (or fails) Spray sends the HTTP response. This behaviour is non-blocking.

  • http://www.michaelhamrah.com/ Michael Hamrah

    Thanks Kafecho, you are correct. Navadava, in order for the call to be blocking there must be an await call, which there is none. Spray’s standard marshalling supports futures, so it will unpack the Success value for the response.

  • navadava

    Thanks for that, I stand corrected.

  • http://open.blogs.nytimes.com/author/mark-grey/ Mark Grey

    Would attaching onSuccess or mapTo change this functionality? I’m curious if calling the complete from within the future will block the actor.

  • http://www.michaelhamrah.com/ Michael Hamrah

    No, the behavior is the same. onSuccess is just a different mechanism for working with futures. onSuccess will only be called if the future completes successfully and “unpacks” the future result. mapTo allows you to convert the result of a future to some specific type.

  • Tushar

    Thanks Michael for this awesome tutorial! Can you suggest me an IDE that you used?

  • http://www.michaelhamrah.com/ Michael Hamrah

    I use VIM, with the vim-scala plugin (https://github.com/derekwyatt/vim-scala).

  • Titan

    Awesoem, no mention of which code goes to which File

    NICE WORK!