The Play framework

The Play framework is a web framework built on top of Akka. It has a proven track record in industry, and is thus a reliable choice for building scalable web applications.

Play is an opinionated web framework: it expects you to follow the MVC architecture, and it has a strong opinion about the tools you should be using. It comes bundled with its own JSON and XML parsers, with its own tools for accessing external APIs, and with recommendations for how to access databases.

Web applications are much more complex than the command line scripts we have been developing in this book, because there are many more components: the backend code, routing information, HTML templates, JavaScript files, images, and so on. The Play framework makes strong assumptions about the directory structure for your project. Building that structure from scratch is both mind-numbingly boring and easy to get wrong. Fortunately, we can use Typesafe activators to bootstrap the project (you can also download the code from the Git repository in https://github.com/pbugnion/s4ds but I encourage you to start the project from a basic activator structure and code along instead, using the finished version as an example).

Typesafe activator is a custom version of SBT that includes templates to get Scala programmers up and running quickly. To install activator, you can either download a JAR from https://www.typesafe.com/activator/download, or, on Mac OS, via homebrew:

$ brew install typesafe-activator

You can then launch the activator console from the terminal. If you downloaded activator:

$ ./path/to/activator/activator new

Or, if you installed via Homebrew:

$ activator new

This starts a new project in the current directory. It starts by asking what template you want to start with. Choose play-scala. It then asks for a name for your application. I chose ghub-display, but go ahead and be creative!

Let's explore the newly created project structure (I have only retained the most important files):

├── app
│   ├── controllers
│   │   └── Application.scala
│   └── views
│       ├── main.scala.html
│       └── index.scala.html
├── build.sbt
├── conf
│   ├── application.conf
│   └── routes
├── project
│   ├── build.properties
│   └── plugins.sbt
├── public
│   ├── images
│   │   └── favicon.png
│   ├── javascripts
│   │   └── hello.js
│   └── stylesheets
│       └── main.css
└── test
    ├── ApplicationSpec.scala
    └── IntegrationSpec.scala

Let's run the app:

$ ./activator
[ghub-display] $ run

Head over to your browser and navigate to the URL 127.0.0.1:9000/. The page may take a few seconds to load. Once it is loaded, you should see a default page that says Your application is ready.

Before we modify anything, let's walk through how this happens. When you ask your browser to take you to 127.0.0.1:9000/, your browser sends an HTTP request to the server listening at that address (in this case, the Netty server bundled with Play). The request is a GET request for the route /. The Play framework looks in conf/routes to see if it has a route satisfying /:

$ cat conf/routes
# Home page
GET     /                           controllers.Application.index
...

We see that the conf/routes file does contain the route / for GET requests. The second part of that line, controllers.Application.index, is the name of a Scala function to handle that route (more on that in a moment). Let's experiment. Change the route end-point to /hello. Refresh your browser without changing the URL. This will trigger recompilation of the application. You should now see an error page:

The Play framework

The error page tells you that the app does not have an action for the route / any more. If you navigate to 127.0.0.1:9000/hello, you should see the landing page again.

Besides learning a little of how routing works, we have also learned two things about developing Play applications:

  • In development mode, code gets recompiled when you refresh your browser and there have been code changes
  • Compilation and runtime errors get propagated to the web page

Let's change the route back to /. There is a lot more to say on routing, but it can wait till we start building our application.

The conf/routes file tells the Play framework to use the method controllers.Application.index to handle requests to /. Let's look at the Application.scala file in app/controllers, where the index method is defined:

// app/controllers/Application.scala
package controllers

import play.api._
import play.api.mvc._

class Application extends Controller {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

}

We see that controllers.Application.index refers to the method index in the class Application. This method has return type Action. An Action is just a function that maps HTTP requests to responses. Before explaining this in more detail, let's change the action to:

def index = Action {
  Ok("hello, world")
}

Refresh your browser and you should see the landing page replaced with "hello world". By having our action return Ok("hello, world"), we are asking Play to return an HTTP response with status code 200 (indicating that the request was successful) and the body "hello world".

Let's go back to the original content of index:

Action {
  Ok(views.html.index("Your new application is ready.")) 
}

We can see that this calls the method views.html.index. This might appear strange, because there is no views package anywhere. However, if you look at the app/views directory, you will notice two files: index.scala.html and main.scala.html. These are templates, which, at compile time, get transformed into Scala functions. Let's have a look at main.scala.html:

// app/views/main.scala.html
@(title: String)(content: Html)

<!DOCTYPE html>

<html lang="en">
    <head>
        <title>@title</title>
        <!-- not so important stuff -->
    </head>
    <body>
        @content
    </body>
</html>

At compile time, this template is compiled to a function main(title:String)(content:Html) in the package views.html. Notice that the function package and name comes from the template file name, and the function arguments come from the first line of the template. The template contains embedded @title and @content values, which get filled in by the arguments to the function. Let's experiment with this in a Scala console:

$ activator console
scala> import views.html._
import views.html._

scala> val title = "hello"
title: String = hello

scala> val content = new play.twirl.api.Html("<b>World</b>")
content: play.twirl.api.Html = <b>World</b>

scala> main(title)(content)
res8: play.twirl.api.HtmlFormat.Appendable =
<!DOCTYPE html>

<html lang="en">
    <head>
        <title>hello</title>
        <!-- not so important stuff -->
    </head>
    <body>
        <b>World</b>
    </body>
</html>

We can call views.html.main, just like we would call a normal Scala function. The arguments we pass in get embedded in the correct place, as defined by the template in views/main.scala.html.

This concludes our introductory tour of Play. Let's briefly go over what we have learnt: when a request reaches the Play server, the server reads the URL and the HTTP verb and checks that these exist in its conf/routes file. It will then pass the request to the Action defined by the controller for that route. This Action returns an HTTP response that gets fed back to the browser. In constructing the response, the Action may make use of a template, which, as far as it is concerned is just a function (arguments list) => String or (arguments list) => HTML.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.98.250