Sunday, February 9, 2014

Develop a REST Service using Play and PostgreSQL on IBM Bluemix: Part One

This post will show how to use the Play framework[1] with IBM Bluemix to develop and run a very simple REST style web application. The application supports APIs to create, retrieve, update and delete objects represented by JSON in HTTP requests. On the backend, the application connects to a Bluemix managed PostgreSQL database to persist and query data parsed out by the application from the HTTP requests. The data used in the application describes a note -- modeled as two fields of text for note's title and its contents. The application is just a sample and is not intended to be used in production. Future posts on this topic are going to describe how to address production concerns such as automated testing, authentication, authorization and more.

Security considerations are entirely out of scope for this post. While the REST API described here has some rudimentary protection against some attacks (e.g. SQL injection), the application should not be used to store sensitive information or be exposed to the web as part of anything other than a learning exercise. More sophisticated security features for the application are topics for future posts.

The steps in this post can be followed without an understanding of SQL, REST and Scala but those who invest some time in getting familiar with these technologies are going to get more value out of the content here.

Connect a Scala application to a PostgreSQL database in the IBM Bluemix environment


Earlier posts explained the basics of the manifest.yml deployment descriptor used for Cloud Foundry based platforms. The manifest used in this post relies on the services capability of Cloud Foundry(CF). The difference between CF applications and CF services amounts to a conceptual difference between units of development (former) and units of reuse (latter). This means that CF applications can depend on (and reuse) CF services but not vice versa. However an appropriately architected CF application[2] can be repackaged and deployed to Cloud Foundry as a service thus becoming a unit of reuse for other CF applications. A detailed explanation of CF services[4] is outside the scope of this post; the example here will focus on describing how to use a PostgreSQL database service available on IBM Bluemix.

In contrast to the manifest files used in the previous posts, manifest.yml for the application described here includes a section declaring services references (line 8 in the following snippet) and a name of a service instance to be available to the application (line 9 in the snippet). The details of how the service is instantiated and the specific parameters that should be used for the service are covered in a later section. The Play application in this post is going to rely on a PostgreSQL database version 9.1


Prepare Play framework code for deployment to IBM Bluemix


Start by downloading and unzipping a standalone distribution of the Play framework[3] to a directory. Before proceeding you will need to make sure that the directory is in your path variable and then execute play new play-rest-api-sample command. Use play-rest-api-sample as the name of your application and choose to create a Scala application as shown in the following snippet.

Before proceeding, change your working directory to play-rest-api-sample created by the play new command and delete build.sbt file as it will interfere with the rest of the build code used in this application.

As with previous posts, you can choose to continue by fetching files from a git repository[10]. If you decide to take the git option, you can skip directly to the Deploy and test section of this post but for a deeper understanding of the code continue to read on from here.

First, you will need to configure the newly created application to take advantage of the database instance specified in the manifest.yml. The framework takes care of database management but to do so it needs the SQL code to create database tables, maintain primary keys and to delete tables in cases when the application is deleted from Bluemix. SQL for the application in this post is shown below. Lines 3-7 define a note table has having an integer ID / primary key and two varchar columns for title and text of a note. Line 9 defines an increasing sequence of numbers starting from 1000 that will be used by PostgreSQL to automatically set the primary key values for the notes added to the database. Lines 13-14 remove both the table and the sequence when the application is deleted.

Once Bluemix instantiates the database, the application can rely on Bluemix to provide the parameter values needed to establish a database connection. Note that in lines 8-10 of the application.conf file in the play-rest-api-sample/conf directory, variables in the cloud.services.notes-db namespace define the values need for the connection.

The application is structured following the Model View Controller (MVC) pattern. The model piece, a file named Note.scala resides in the play-rest-api-sample/app/models directory. The Note Scala case case represents possible values for a note, while the Scala object (snippet below) in the file defines key methods responsible for performing create, retrieve, update and delete (CRUD) operations on the Note tables in the PostgreSQL database.


Notes.scala (shown below) implements the controller piece of the application. For each of the CRUD operations this Scala object mediates between HTTP requests and the Note object by parsing HTTP parameters and data fields and relying on Note to perform database transactions.

The routes file located in the play-rest-api-sample/conf directory instructs the Play framework as to which of the Notes.scala controller methods to invoke depending on the URL of the HTTP request to the application.

Finally, before the application can be compiled, some of the build files need to be modified to an earlier versions of SBT supported by Cloud Foundry. To complete the changes


  • replace the contents of play-rest-api-sample/project/build.properties with

    sbt.version=0.12.2
  • modify the line in play-rest-api-sample/projects/plugins.sbt that starts with addSbtPlugin to be

    addSbtPlugin("play" % "sbt-plugin" % "2.1.1")
  • create a Build.scala file in play-rest-api-sample/projects with the following contents




Build, deploy and test a Play REST application on IBM Bluemix


To build a deployable binaries for the sample application, run play dist from the command line with  play-rest-api-sample as the working directory. Once the build completes, check for the existence of a dist/playrestapisample-1.0.zip file.

You will also need to run the following sed script to create a unique URL for your application by replacing $RANDOM string in the manifest.yml.template file with a random number and writing the result to manifest.yml.


As you recall from the beginning of this post, the application depends on a PostgreSQL service instance which is declared as notes-db in the manifest.yml file. For a more detailed explanation of service instantiation and service binding, have a look at PostgreSQL for IBM Bluemix[5] documentation. Before the application can be deployed, this service instance should be created using cf create-service command as shown in the following snippet. As with earlier posts on this blog, your create-service session with have a different value instead of the <Your IBM ID> string.


Next, issue a cf push command and note that the URL provisioned for the application should match the one in your manifest.yml file.


The following session illustrates the use of the REST API with curl utility. Note that you will need to replace the Bluemix URL in the session with the URL returned to you by cf push. Lines 1-2 show an HTTP POST to create a new note which is assigned an ID of 1000 by the application. The existence of the new note object is confirmed with the GET request show in lines 4-5. In lines 7-8, the note is modified with an HTTP PUT which is then confirmed by querying all of the notes available from the application via a GET request shown on lines 10-11. The final part of the session involves creation of another note which is assigned an ID of 1001 (lines 13-14) while the original note is deleted in lines 16-17. Correct completion of the deletion request is confirmed through query for all notes in lines 19-20. The result of the query shows that the original note with an ID 1000 no longer exists.


References


[1] http://engineering.linkedin.com/play/play-framework-democratizing-functional-programming-modern-web-programmers
[2] http://docs.cloudfoundry.com/docs/running/architecture/services/api.html
[3] http://www.playframework.com/documentation/2.2.x/Installing
[4] http://docs.cloudfoundry.com/docs/running/architecture/services/
[5] https://www.ng.bluemix.net/docs/Services/PostgreSQL/Index.html

[10] Instead of using git clone, which will not overwrite files in your play-rest-api-sample directory, use the following sequence of git commands
git init
git remote add origin https://github.com/cosipov/play-rest-api-sample.git
git fetch origin
git checkout -b master --track origin/master --force