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…
@+
Leave a comment