spray based rest api
Spray is an open-source toolkit for building REST/HTTP-based integration layers on top of Scala and Akka. Being asynchronous, actor-based, fast, lightweight, modular and testable it’s a great way to connect your Scala applications to the world.
TLDR;
This post will give you a example of how to use spray to build a REST api.
Problem
you want to build a REST api that support the following operations:
GET /users/:id
POST /users
routing
spray-routing
gives you a elegant DSL to build routing system, which will accept http request and respond correctly. let’s see the example:
The MyService
trait extends spray.routing.HttpService
which includes a bunch of convinient mehtods for creating DSL, such as path
, get
, complete
.
The variable myRoute
defines a set of rules:
- When a http request matches
GET /users/:id
, calluserRepo.get
with extracteduserId
, and response with the result. - When a http request matches
POST /users/
, calluserRepo.save
with extracteduserData
, and response correponded status code.
Note that there is a field defined as val userRepository: UserRepository
not be initialized. This field will be implemened in a acturall actor (MyServiceActor
in this example).
The actural business logic was deleagted into this object.
json support
I haven’t find a JSON library in Java/Scala world which providing as good api as Ruby doses. if you konw one please let me know.
spray-json is the most beautiful one I ever found!
spray-json
allows you to convert between:
- String JSON documents
- JSON Abstract Syntax Trees (ASTs) with base type JsValue
- instances of arbitrary Scala types
in this post, we just want to convert between JSON documents and Scala case class. To enable JSON serialization/deserialization for your case class, just define a implicit method which returns a instance of RootJsonFormat[YourCaseClass]
.
Put them together
As we metioned before, Spray
is built on top of Scala and Akka,
to enable MyService
to handle http request, we need to create a actor:
This actor mixin MyService
, in the receive
method,
call runRoute
to handle http request with pre-defined route.
A Tips:
put your business logic in plain scala object instead of actor.
I found that it is really hard to test logic in a actor, so I preferred to implate business logic in a pure scala class, then it is much easier to test it. then inject a instance of this class into a actor.
The full exmaple can be found here.