Writing our Play application from scratch

There’s no doubt it’s much better to use a template or in this case a seed (as outlined in my previous post Starting out with the Playframework (in IntelliJ)) set of code to get us up and running with any application, but I like to know what’s going on with my code, I’m not mad on just leaving it as “magic happens”.

So here’s me, reverse engineering the Play seed and creating my own code from scratch. You should be able to work through each step and at the end, you’ll end up with a single page “Hello World” app.

Lets get all the bits in place…

Creating the Project

From IntelliJ

  • Go to File | New Project
  • Select Scala | SBT
  • Name your project
  • Ensure correct Java and Scala versions selected
  • Press Finish

Add support for the Play plugin

Select the project node in the package/project (sources root) treeview and right mouse click on it, select new file and name the file plugins.sbt, place the following into it

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.14")

this will add the Play plugins

Edit the build.sbt

Now open build.sbt and add the following below the scalaVersion line

lazy val root = (project in file(".")).enablePlugins(PlayScala)

libraryDependencies += filters
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "2.0.0" % Test

Note: I had to change the scalaVersion to 2.11.11 to get this code to work, obviously it could be a versioning issue on my part, otherwise I got unresolved dependencies.

Click Enable Auto-Import

Add a gradle build file

Add a new file at the same level as the build.sbt and name it build.gradle. Add the following

plugins {
    id 'play'
    id 'idea'
}

task wrapper(type: Wrapper) {
    gradleVersion = '3.1'
}

repositories {
    jcenter()
    maven {
        name "typesafe-maven-release"
        url "https://repo.typesafe.com/typesafe/maven-releases"
    }
    ivy {
        name "typesafe-ivy-release"
        url "https://repo.typesafe.com/typesafe/ivy-releases"
        layout "ivy"
    }
}

def playVersion = '2.5.14'
def scalaVersion = '2.12.2'

model {
    components {
        play {
            platform play: playVersion, scala: scalaVersion, java: '1.8'
            injectedRoutesGenerator = true

            sources {
                twirlTemplates {
                    defaultImports = TwirlImports.SCALA
                }
            }
        }
    }
}

dependencies {
    ['filters-helpers', 'play-logback'].each { playModule ->
        play "com.typesafe.play:${playModule}_$scalaVersion:$playVersion"
    }
}

Configuration folder

Now Add a conf folder at the same level as the project folder (i.e. just select the root, right mouse click, select new directory and name it conf). Select the conf folder, right mouse click and select Mark Directory As… and select Unmark as Resource Root.

Right mouse click on the conf directory, select New File and name it routes (it’s just a text file). Place the following in the file

GET   /   controllers.IndexController.index

Add another file to conf named application.conf. We’re not actually putting anything in this file.

Create the app folder

Now, again at the root level, create another directory named app and Unmark as Source Root. In this directory add a controllers directory and views.

In app, add a new file named Filters.scala and add the following to it

import javax.inject.Inject

import play.api.http.DefaultHttpFilters

import play.filters.csrf.CSRFFilter
import play.filters.headers.SecurityHeadersFilter
import play.filters.hosts.AllowedHostsFilter

class Filters @Inject() (
   csrfFilter: CSRFFilter,
   allowedHostsFilter: AllowedHostsFilter,
   securityHeadersFilter: SecurityHeadersFilter
   ) extends DefaultHttpFilters(
  csrfFilter,
  allowedHostsFilter,
  securityHeadersFilter
)

Add the controllers and views

Okay, before we’ll actually see anything of use we need controllers and views, but in essence at this point you can create a configuration (SBT Task) with the Task run and should be able to run the http server up and see an error as it cannot find the IndexController (at least this gives us the feeling we’re almost there).

Now in the app/controllers folder add a new file named IndexController.scala and place the following code in it

package controllers

import javax.inject._
import play.api._
import play.api.mvc._

@Singleton
class IndexController @Inject() extends Controller {
   def index = Action { implicit request =>
      Ok(views.html.index())
   }
}

and now we need the index view so in app/views add an index.scala.html file and a main.scala.html (this will be our main entry point and the index maps to out IndexController). So the main file should look like this

@(title: String)(content: Html)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>@title</title>
    </head>
    <body>
@content
    </body>
</html>

and index.scala.html should look like this

@()

@main("Hello World") {
<h1>Hello World</h1>
}

Note: the @main passes Hello World through to main.scala.html and that file creates the equivalent of an input argument @(title: String) and (content: Html) the title is what’s passed from index.scala.html in the @main argument.

Now run up the application and using your browser check http://<ip_address>:9000 and you should see the results of your index.scala.html displayed – “Hello World”.

You might feel a little familiar with the @ commands in the html files – these are template commands which the Play Template Engine provides – they’re similar to the likes of Razor and other templating engines.

So for example we might take the request (passed into our IndexController and inject into out html template like this

def index = Action { implicit request =>
  Ok(views.html.index(name = request.rawQueryString));
}

and in the index.scala.html

@(name: String)

@main("Hello World"){
<h1>Hello @name</h1>
}

Now if we navigate to this http://localhost:9000/?Parrot in our browser, we should see Hello Parrot displayed.

Next steps

Unlike the seed code, I removed all CSS, JavaScript etc. In the seed application off of root we have a public directory with public/images, public/javascripts and public/stylesheet. To make these folders available to our *.scala.html files, we need to add a route to the conf/routes file, for example

GET     /assets/*file               controllers.Assets.versioned(path="/public", file: Asset)

Now, in our *scala.html files we can access these aseets using code such as

@routes.Assets.versioned("javascripts/main.js")"

here’s the seed main.scala.html file to demonstrate including stylesheets, images and scripts

@(title: String)(content: Html)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>@title</title>
        <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">

    </head>
    <body>
        @content
      <script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
    </body>
</html>

Logging

Obviously, once we really get going with our code we’ll probably want to start logging interactions. Play comes with a default logger built in which is as simple to use as this

  • import play.api.Logger
  • Logger.debug(“Some String”)