Building a chat service using Scala, Spray, MongoDB and Casbah

Post from August 28th, 2015

So, one day, I decided to make a chat, and why not?, it could be a REST service!

In terms of security, it’s not really secure, as it could be DDoS’ed really simply, but in terms of learning I thought it would be a really rich experience.

So the API would work like this:

I would have two paths:
- /getMessages
- /sendMessage

The first one would return to me a list of messages, each message would have an ID and the content. If an integer argument is passed we would return just only the message corresponding to that ID.

The second one would take an argument of a percent-encoded string, storing it in the database.

I based this message system on the 4chan message board. Users are “completely” anonymous and they would refer to each other using the message ID.

So, we define our first test:

"The REST api" should "return an empty list on GET when there are no messages" in {
Get("/getMessages") ~> avocadoRoute ~> check {
responseAs[String] should be("")

And now, we write the code to pass it:

package com.nickseagull.avocado
import spray.routing._
import spray.http._
import MediaTypes._
class AvocadoServiceActor extends Actor with AvocadoService {
def actorRefFactory = context
def receive = runRoute(avocadoRoute)
trait AvocadoService extends HttpService {
val avocadoRoute = {
get {
pathSingleSlash {
respondWithMediaType(`application/json`) {

Defining this service in a trait and not in the actor itself allows us to make our REST API more modular, and in case that our project grows, we would not have an enormous file containing all of our routes.

Now, we define our second test:

it should "be able to POST a message" in {
Post("/sendMessage/message") ~> sealRoute(avocadoRoute) ~> check {
responseAs[String] should be("Message sent successfully")

And we write the code for it:

trait AvocadoService extends HttpService {
val avocadoRoute = {
path("getMessages") {
get {
respondWithMediaType(`application/json`) {
} ~
path("sendMessage" / Segment) { message =>
post {
complete("Message sent successfully")

As we can see, Spray has a really straightforward API, and for the sake of brevity, we will not write all of our code in this post, but only the important part.

Now we need our database set-up.
I made a singleton just for being quicker, but the correct way should be doing it with some monads to encapsulate side-effects.

So, we connect to our database, and to the collection “messages”:

val messages = MongoClient("localhost", 27017)("avocado")("messages")

Casbah provides some really nice way to connect to it.

We define a method to get all our messages:

def getMessages:List[Message] = messages.find().map(buildMessage).toList

Ahhh, one liners, how I love you :)

But, what is buildMessage?

def buildMessage(x: DBObject): Message = Message(getId(x), getContent(x))
def getId(x: DBObject): Int = x.getAs[Int]("_id").getOrElse(-1)
def getContent(x: DBObject): Int = x.getAs[String]("content").getOrElse("")

Of course all of them are private, we don’t want anyone to use these.

To get just one message we could write this:

def getMessageById(id: Long): Message =
findOne(MongoDBObject("_id" -> id)).
getOrElse(MongoDBObject("_id" -> -1,"content" -> "Message not found"))

To send a message I succumbed to mutability (OH NO!). In my defense I want to say that I did it because I didn’t want to mess with monads in Scala as I did not have previous experience using them in this language. And, before you say it, no, passing the DB connection from one function to another was not an option.

So I added a var (dang, it hurts me more than it hurts you) to count the number of messages.

var messageCount = 0; // THIS IS EVIL!!!

And I added a sendMessage method:

def sendMessage(m: String) = {
private def unsafeInsertMessage(m: String) {
val message = MongoDBObject(
"_id" -> messageCount,
"content" -> m
messageCount+=1 // More evil

Oh, and of course, a clear method to erase all of the messages.

def clear {
messageCount = 0

After this we just need to write some more tests and finish our REST API.

You can see the “finished” project on my GitHub. (I say “finished” because I need to “exorcise” all of that evil mutability from the code and add some monads someday).

Thanks for reading!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.