Lightbend Activator

Play Framework with REST, ReactiveMongo and Polymer

Play Framework with REST, ReactiveMongo and Polymer

JAVEO
Source
November 4, 2015
playframework scala mongo reactivemongo polymer

A starter application with Play Framework, ReactiveMongo and Polymer employing REST services.

How to get "Play Framework with REST, ReactiveMongo and Polymer" on your computer

There are several ways to get this template.

Option 1: Choose play-reactivemongo-polymer in the Lightbend Activator UI.

Already have Lightbend Activator (get it here)? Launch the UI then search for play-reactivemongo-polymer in the list of templates.

Option 2: Download the play-reactivemongo-polymer project as a zip archive

If you haven't installed Activator, you can get the code by downloading the template bundle for play-reactivemongo-polymer.

  1. Download the Template Bundle for "Play Framework with REST, ReactiveMongo and Polymer"
  2. Extract the downloaded zip file to your system
  3. The bundle includes a small bootstrap script that can start Activator. To start Lightbend Activator's UI:

    In your File Explorer, navigate into the directory that the template was extracted to, right-click on the file named "activator.bat", then select "Open", and if prompted with a warning, click to continue:

    Or from a command line:

     C:\Users\typesafe\play-reactivemongo-polymer> activator ui 
    This will start Lightbend Activator and open this template in your browser.

Option 3: Create a play-reactivemongo-polymer project from the command line

If you have Lightbend Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME play-reactivemongo-polymer on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/JAVEO/play-reactivemongo-polymer#master.

Option 5: Preview the tutorial below

We've included the text of this template's tutorial below, but it may work better if you view it inside Activator on your computer. Activator tutorials are often designed to be interactive.

Preview the tutorial

Play Framework - ReactiveMongo - Polymer

The purpose of this application is to demonstrate a Service Oriented Approach for Single Page App development.

To serve this purpose this application template integrates Polymer, Play Framework and MongoDB.

Database

A document based NoSQL MongoDB database is used along with ReactiveMongo driver to connect to it in asynchronous, non-blocking way.

To install MongoDB on your computer you can use this manual.

To connect to database Play-ReactiveMongo plugin is used. To make it work the following has been done:

  1. Adding dependency in build.sbt
    "org.reactivemongo" %% "play2-reactivemongo" % "0.11.7.play24"
  2. Adding plugin in play.plugins
    1100:play.modules.reactivemongo.ReactiveMongoPlugin
  3. Adding database url in application.conf
    mongodb.uri = "mongodb://localhost:27017/posts"

REST API

The application tier is delivered by a simple Play app. This way you can easily take advantage of Play's ecosystem, eg. add some plugins or other benefits, such as Akka, CoffeScript support Web Sockets and many, many more. The template has one Controller: Posts. It has PostRepo which uses Play-ReactiveMongo plugin under the hood.

PostRepo provides db object to access specific database collections:

                
                    protected def collection = db.collection[JSONCollection]("posts")
                
            

To get data from the database use list method. It's use looks like this:

                
                    def list = Action.async {implicit request =>
                        postRepo.find()
                        .map(posts => Ok(Json.toJson(posts.reverse)))
                        .recover {case PrimaryUnavailableException => InternalServerError("Please install MongoDB")}
                    }
                
            
In this case the response is json with all posts from the database collection:
                
                    [
                        {
                        "_id": {"$oid":"556848238600001401dfead6"},
                        "text" : "Have you heard about the Web Components revolution?",
                        "username" : "Eric",
                        "avatar" : "../images/avatar-01.svg",
                        "favorite": false
                        },
                        {
                        "uid": {"$oid":"556848238600001401dfead7"},
                        "text" : "Loving this Polymer thing.",
                        "username" : "Rob",
                        "avatar" : "../images/avatar-02.svg",
                        "favorite": false
                        },
                        ...
                    ]
                
            

To like post : In the template it accepts json body with favorite, boolean flag. The method saves this flag in the database collection:

                
                    def like(id: String) = Action.async(BodyParsers.parse.json) { implicit request =>
                        val value = (request.body \ Favorite).as[Boolean]
                        postRepo.update(BSONDocument(Id -> BSONObjectID(id)), BSONDocument("$set" -> BSONDocument(Favorite -> value)))
                        .map(le => Ok(Json.obj("success" -> le.ok)))
                    }
                
            

To update post's message : In the template it accepts json body with text, String parameter:

                
                    def update(id: String) = Action.async(BodyParsers.parse.json) { implicit request =>
                        val value = (request.body \ Text).as[String]
                        postRepo.update(BSONDocument(Id -> BSONObjectID(id)), BSONDocument("$set" -> BSONDocument(Text -> value)))
                        .map(le => Ok(Json.obj("success" -> le.ok)))
                    }
                
            

To delete post :

                
                    def delete(id: String) = Action.async {
                        postRepo.remove(BSONDocument(Id -> BSONObjectID(id)))
                        .map(le => RedirectAfterPost(le, routes.Posts.list()))
                    }
                
            

To add post :

                
                    def add = Action.async(BodyParsers.parse.json) { implicit request =>
                        val username = (request.body \ Username).as[String]
                        val text = (request.body \ Text).as[String]
                        val avatar = (request.body \ Avatar).as[String]
                        postRepo.save(BSONDocument(
                            Text -> text,
                            Username -> username,
                            Avatar -> avatar,
                            Favorite -> false
                        )).map(le => Redirect(routes.Posts.list()))
                    }
                
            

To expose REST API in Play framework the routes file has been configured:

                
                    GET     /api/posts                  controllers.Posts.list
                    PATCH   /api/post/:id/like          controllers.Posts.like(id: String)
                    PATCH   /api/post/:id               controllers.Posts.update(id: String)
                    POST    /api/post                   controllers.Posts.add
                    DELETE  /api/post/:id               controllers.Posts.delete(id : String)
                
            

Frontend

Frontend is based on Polymer which uses Web Components. It's a very prospecting technology, promising true component development of the web.

For sake of this template this sample app available on Polymer website has been used.

All resources from the sample app have been copied to public directory in Play application. (We are looking forward to publishing polymer and web components as webjars in the future to use them as dependencies instead). Application is built from the post-list element which represents a list of posts. A single post is represented by the post-card element.

Polymer elements encapsulate template for view and script for behavior:

                
            <dom-module id="unique-id">
                <template>
                    ...
                </template>
            </dom-module>

            <script>
                Polymer({
                    is: 'unique-id',
                    ...
                });
            </script>
                
            

Use data binding in your markup to fill your template with data:

                
    <img src="[[item.avatar]]" width="70" height="70">
    <h2>[[item.username]]<h2>
                
            

Communication

The core-ajax component in post-service element is used to call backend REST services from Polymer:

                
    <iron-ajax id="ajax"
               url="/api/posts"
               handle-as="json"
               last-response="{{posts}}">
    </iron-ajax>
                
            

The posts element attribute is public and can be used by other elements:

                
    <post-service id="service" posts="{{posts}}" ...></post-service>
                
            

To set favorite flag for a post you have to call the like REST URL. Specify the HTTP method, url, body and contentType:

                
    <iron-ajax id="likeCall"
               method="PATCH"
               content-type="application/json"
               handle-as="json"
               on-response="refresh">
    </iron-ajax>
                
            

To make the call bind your parameters and invoke go method on the like-call iron-ajax component:

                
    setFavorite: function(id, isFavorite) {
        this.$.likeCall.url = '/api/post/' + id + '/like';
        this.$.likeCall.body = JSON.stringify({ "favorite": isFavorite });
        this.$.likeCall.generateRequest();
    }
                
            

Summary

MongoDB and Play Framework are a great mix to implement backend web services, easy to integrate with contemporary UI frameworks.

Thanks to Mongo you can store data without worrying about the schema and Play can expose this data very easily via REST API.

It is a very powerful technology stack with the UI in cutting edge Polymer library and Web components.