Scala – Scalatra – Salat – MongoDB : test drive

CodeDevEnglishTutorials

Hello there, a little test with Scala (2.9.0-1) for the backend services, Scalatra for the REST part, Salat and MongoBB for the persistance layer. I will use sbt (0.10) for the project management and you should use IntelliJ Idea IDE (what else ? ).

What this test does ?

It exposes a REST API (and its documentation) in order to play with a user (login, email, password). This API is extremely simplified, so you understand easely the concepts.
The objective is to :
– add a user,
– get a user (with its id or login),
– delete a user
– have the API documentation online for each method

MongoDB installation :

wget -c http://www.mongodb.org/dr/fastdl.mongodb.org/linux/mongodb-linux-x86_64-1.8.2.tgz/download
tar xzf mongodb-linux-x86_64-1.8.2.tgz
rm -f mongodb-linux-x86_64-1.8.2.tgz
cd mongo
sudo mkdir -p /data/db/
sudo chown <code>id -u</code> /data/db
bin/mongod

Ok Mongo DB is running.

Run the project
So youll know what it does, we will look how it works after that.

Here is the working project, either clone it from github:

git clone git://github.com/jrevault/ScalaScalatraSalatMongoDB.git

or download it:
https://github.com/jrevault/ScalaScalatraSalatMongoDB/zipball/master
Just uncompress it somewhere, open a terminal (command-line for some) and do :

julien@mars:/data/DEV/ScalaScalatraSalatMongoDB$ sbt

Obviously if you didn’t install sbt it will not work! Go there: https://github.com/harrah/xsbt/wiki/Setup

So let’s continue, after you run the sbt command you have something like this :

julien@mars:/data/DEV/ScalaScalatraSalatMongoDB$ sbt
Getting net.java.dev.jna jna 3.2.3 ...
:: retrieving :: org.scala-tools.sbt#boot-app
        confs: [default]
        1 artifacts copied, 0 already retrieved (838kB/36ms)
Getting Scala 2.8.1 (for sbt)...
:: retrieving :: org.scala-tools.sbt#boot-scala
        confs: [default]
        4 artifacts copied, 0 already retrieved (15296kB/315ms)
Getting org.scala-tools.sbt sbt_2.8.1 0.10.0 ...
:: retrieving :: org.scala-tools.sbt#boot-app
        confs: [default]
        34 artifacts copied, 0 already retrieved (6012kB/344ms)
[info] Set current project to default (in build file:/data/DEV/ScalaScalatraSalatMongoDB/project/plugins/)
[info] Updating...
[info] Done updating.
Getting Scala 2.9.0-1 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
        confs: [default]
        4 artifacts copied, 0 already retrieved (20447kB/278ms)
[info] Set current project to default (in build file:/data/DEV/ScalaScalatraSalatMongoDB/)
> 

Everything seems fine, sbt has found all dependencies, now you can launch the jetty server :

> jetty-run

It will compile and run a jetty server accessible at : http://localhost:8080

The home page is managed by the ScalaScalatraSalatMongoDB/src/main/scala/fr/quidquid/rest/SSMBaseFilter.scala file particulary this method :

get("/") {
  <html>
    <body>
      <h1>Hello tarie! (a very stupid french word game)</h1>
      Say <a href="hello-scalate">hello to Scalate...</a>.
    </body>
  </html>
}

As you can see the get(“/”) method listens to all http://localhost:8080/ calls, and we can put directly html.

Now for this to work open the ScalaScalatraSalatMongoDB/src/main/webapp/WEB-INF/web.xml file wich declares the SSM_base scalatra filter :

<filter>
  <filter-name>SSM_base</filter-name>
  <filter-class>fr.quidquid.rest.SSMBaseFilte</filter-class>
</filter>
<filter-mapping>
  <filter-name>SSM_base</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Inside the web.xml file we also declare the SSM_user scalatra filter :

<filter>
  <filter-name>SSM_user</filter-name>
  <filter-class>fr.quidquid.rest.SSMUserFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>SSM_user</filter-name>
  <url-patter>/api/user/*</url-pattern>
</filter-mapping>

This one will listen to all /api/user/* url calls, the real API REST service.

Below this servlet another one, called SSM_user_doc, listens to all /doc/user/* url calls, this one is for the API documentation.

In order to add a user inside MongoDB we have to call the /api/user/add REST service.
To know how it works call its documentation :
http://localhost:8080/doc/user/add

Now that you know how it works, add a user :
http://localhost:8080/api/user/add/julien@ledruide.com/julien/ChUtcHuT

You can see into the console the ID generated by MongoDB (4e30622644aefeb51e57b6a4 in my case)

Now use the http://localhost:8080/doc/user/get API to find your user back :
http://localhost:8080/api/user/get/4e30622644aefeb51e57b6a4

If you want to delete a user, read the api doc there :
http://localhost:8080/doc/user/delete

for instance :
http://localhost:8080/api/user/delete/4e30622644aefeb51e57b6a4

Behind the scene
Sources are inside: ScalaScalatraSalatMongoDB/src/main/scala/ folder.
I have 3 main packages :
fr.quidquid.rest
All the rest interfaces that listens for URL calls and returns JSON data (for instance I return everything into text/html for browser testing reasons, you can change this behavior in the beforeSome method of the SSMBaseFilter scala class.
A subpackage fr.quidquid.rest.doc exposes the API DOC scaml pages inside ScalaScalatraSalatMongoDB/src/main/webapp/WEB-INF/scalate/apidocs/ (and this should be automated, but this is not the purpose here).

– fr.quidquid.services
A very simple service layer that is the junction between front and domain layers. The services does the business logic stuff.

– fr.quidquid.domain
The domain layer containing models and DAOs

Now we can follow step by step the add user example

ScalaScalatraSalatMongoDB/src/main/webapp/WEB-INF/web.xml defines the SSM_user filter and when the /api/user/add URL is called scalatra does all the magic and forwards the call to the fr/quidquid/rest/SSMUserFilter.get(“/api/user/add/:email/:login/:password”) method.
As you can see inside the code, to access a URL parameter is reaaaly simple :

params( "login" )

So this method gets the 3 parameters of the URL and calls the fr/quidquid/services/UserService.add( login:String, password:String, email:String ):User method (I know this method returns a model object and that it is bad but this is a fast tutorial, no time for VO or DTO or DO or whatever you call them)

The service instanciates a User model and uses the ultra simple DAO (thanks to Salat) in order to store it inside database.

val obj = new User( login = login, password = password, email = email )
UserDao.insert(obj)

The DAO file is there : fr/quidquid/domain/mongo/User.scala

object UserDao extends SalatDAO[ User , ObjectId ](collection = MongoConnection()("quidquid")("user"))

Then the service retrieves the complete User object :

UserDao.findOneByID(id.get).get

and send it back to the rest layer where we transform the object into a JSON notation (thanks to jerkson) :

Json.generate(obj)

Now your turn

Before changing the code and play with everything type inside your sbt console:

> ~prepare-webapp

in order to compile and deploy into jetty as soon as you change an object! Cool!

Now just play with the code and add your own APIs onto the noosphere…
@+

Previous
Scala – Scalatra – Salat – MongoDB : découverte
Next
3 minutes SVN server

Leave a comment

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.