In this post I will try to explain simple rest api made in Akka http, Slick and PostgreSql. Here is git repo: Github repo
A) What is akka http?
Docs: Akka http docs
Zalando presentation: Zalando
Much more advanced akka http example which was great help for me, when doing my example: ArchDev example
B) What is slick?
Docs: Slick docs
Fantastic presentation by Stefan Zeiger: Stefan Zeiger presentation
A) Project structure
This is structure of sbt project. Check
to see what dependencies has been used in this project. Whole structure should look similar to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
I use postgresql, example of configuration of database you can find in
So create your own application.conf inside
Schema is as simple as it could be:
I use flyway for database migration so you can preview .sql files in
C) Project configuration
Main.scala is an entry point to our application
1 2 3 4 5 6 7 8 9 10
As you see there is initialization of required variables. We should start ActorSystem(), create executor and materializer. There is also binding of http request to our routes. We will go back to it later.
object Main extends many other objects, App of course, but also other like Config.
1 2 3 4 5 6 7 8 9 10 11
I will not copy the documentation: Akka configuration docs
Next file is MigrationConfig.scala:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Here we’ve got initialization of flyway object, we setup it with proper database values(they come from Config.scala). There are two methods, one for running migrations and second for reloading schema.
And the last ‘extention’ is Routes.scala
1 2 3 4 5 6 7 8
As you suppose this is highest level of our api routes. There is specified some prefix, and default route. Routes are extending some objects but we will go back to them later.
III. Rest Api
Ok so what about that Routes.scala. It is our ‘dispatcher’ which will match http requests to proper actions. Let’s focus on ApiErrorHander which trait Routes extends:
1 2 3 4 5 6 7 8
I made this implicit because I want each error, which I suppose to happen in my application, recover in one place. I can do this because each layer of my application is returning Future object, so everything is wrapped up in this monad, our errors will be safely wrapped up and at the end of the world (so in our case ApiErrorHandler) we will recover them. NoSuchElementException will be thrown, for example, when you would like to GET user with non existing id. And because this is implicit all I need is just extend that object, and I have this recover part code in proper scope.
Exception handling in docs: Akka exception handling docs
Now, lets look at Users api:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Everything here should be self explanatory: You’ve got some path, rest method definition, and response when Dao method will be completed. Users Dao methods are returning Future so we’ve got to ‘unpack’ it with value by using map and we need to transform result to json. You should notice that UsersApi is extending JsonMappings:
1 2 3 4 5
I placed here all json formats objects which will implicitly transform object to json. Without it you will get compilation error because if you see signature of method toJson():
It expects implicit object of type JsonWriter and this part:
Creates JsonWriter[User] and JsonReader[User] so our api methods can transform scala object to json and json to scala object.
Ok last layer is DAO. Let’s look at UsersDao:
1 2 3 4 5 6 7 8 9 10
This should look familiar to you, even if you were not using slick. We are creating sql queries and send them to db. When you will look in docs you will see that each slick statement like this one for example:
Should be done within db.run() method (where db is config variable from DatabaseConfig.scala). So those Dao methods should look like this:
etc. It would be tedious to write this boilerplate code. This is why we have implicits :)
Look at BaseDao which UsersDao extends:
1 2 3 4 5 6 7 8 9 10 11 12
We’ve got here initialization of TableQuery objects, which are representation of tables in db, and some implicit methods. Those methods transforms result of other methods. But which one? Those one who are explicitly said that should return Future[A] or Future[Seq[A]] but instead they are returning SqlAction or FixedSqlStreamingAction(Which are results of building query in slick, so our DAO methods are example of those). So those methods apply db.run to this SqlAction and FixedSqlStreamingAction objects and this is how we avoid writing db.run(…) each time we want to call dao method.
I tested those api methods using scalatest. Check it out ;)
Akka http is additional layer on top of akka which helps you communicate with actor system via Http requests. With a little effort you can build webservice easily. Akka http is very flexible and lightweight so it is not some kind of ‘fullstack’ framework but maybe you should consider using it in your future project.
Thanks for checking out this post, if you have any questions, feel free to comment or contact ;)