Play! is a web framework for Java and Scala. Play promises to bring the developer productivity of web frameworks like Ruby on Rails to the Java and Scala languages. Of course, it wouldn’t make much sense just to copy Rails. So Play adds its own spin: Play 2.0 is fully statically type checked, giving the developer quick feedback when something doesn’t make any sense.
Now that Play 2.0 is getting closer to final release I took some time to dive in. Here are my first impressions, using the Scala APIs.
- Automatic recompile on refresh gives you extremely quick feedback.
- High modularity makes Play easy to learn, use, and extend.
- Very easy deployment to production environments.
- Type safe templates and routes make it easier to keep your application consistent.
- High performance with support for both synchronous and asynchronous HTTP handling.
- Java and Scala APIs are quite similar, so should allow easy transfer of skills.
- Sessions are simple cookies, making it easy to scale or perform zero-downtime upgrades.
- Support for WAR packaging is not planned until 2.1. This is needed if you need to deploy in a Servlet Container.
- Not backwards compatible with the older Play 1.x framework.
conf/routesformat instead of simple DSL like Scalatra or spray.cc.
- Many APIs rely on singletons (Scala) or static methods (Java), which can make testing challenging. However, fake implementations of the main abstractions are provided (Application, Request, etc).
Out of the box experience
Getting started with Play is straigthforward. Just download the distribution, unpack it, and add it to your $PATH. After that type
play new my-app, select your application’s name (defaults to
my-app in this example), and type (Scala, Java, or empty). After choosing the Scala application type I ended up with a new directory containing just a few directories and files (with just 19 lines of Scala code and 17 lines of HTML templates).
Starting the application is as easy as typing
play run and pointing your browser to http://localhost:9000/. The initially load takes a while as it needs to compile templates and Scala sources. After the page loads you get a nice explanation what to do next and plenty of documentation links:
Controllers and templates
The first thing you encounter in any web framework is to mapping from HTTP requests to your code. In Play this is extremely straightforward. The request method and path are located in the
conf/routes file and the indicated method is invoked in your controller. An example route entry is:
GET / controllers.Application.index
So whenever the home page is requested the
controllers.Application.index method is invoked. Notice that you’ll get a compile time error if this method does not exist or requires parameters. So if you add the following to the
GET /:page controllers.Application.page(page, format ?= "html")
and refresh your browser you’ll quickly see an error message:
Fixing this is easy, just add the missing method to the
As you can see a controller action is just a method that returns an
Action in turn returns an
Ok response, which translates into a HTTP
200 OK response. What I like here is that the controller method is directly linked from the
conf/routes file without me having to remember any mapping conventions. There is also no complicated rendering pipelines that are typically associated with component based web frameworks like JSF or Wicket.
In this action we directly returned a piece of HTML. It is also possible to use templates. Let’s change the index page to link to our new controller action. By changing the
index.scala.html template to:
a new link is rendered that maps to the new route. After refreshing the browser you can now click the link to navigate to your new page action. Extremely straightforward and especially nice is the use of type safe URLs and the light-weight template syntax (just using the
@ sign to add some Scala code in your HTML template).
Also nice is that templates are turned into ordinary methods (with the first line of the template becoming the parameter list) that can be called from controllers, other templates, or tests. In the template above the
main template is invoked to render layout around the provided link.
Play also has support for forms, validation, and binding form data to domain objects. Unlike most other web frameworks it is not necessary to alter your domain objects to use them with forms. Specifically, there is no need to add a default constructor or any setters. Here is an example domain object
User with a form definition:
The form defines two fields with validation and the mapping from the form fields to the domain object (in this case by using the Scala generated
register action uses the form definition to perform validation and bind data from the request to the domain object. In case of errors, the page is rerendered with the validation errors. Otherwise a new user instance is available (and in this case a simple redirect is performed, a real application would probably save the user somewhere). Notice that it is not possible to get a (partially) invalid user object, unlike most other form validation frameworks (like Ruby on Rails, Spring MVC, and Wicket).
To render the form there are some predefined form helpers (also available in Twitter Bootstrap variant). Unfortunately the field names are not statically checked against the form definition:
Play comes with built-in support for SQL/JDBC databases. The simplest way to use this to first enable the datasource in
Then add a schema evolution file
When you refresh the browser Play will notify you that you need to apply the schema migration:
Pressing the ‘Apply this script now!’ button will immediately perform the database migration.
Now that we have a running database it is easy to query using the JDBC API and the Anorm wrapper library:
DB.withTransaction gives you a plain JDBC connection it is also easy to use any other Java or Scala tool to handle database persistence.
Deploying a Play application is easy. My preference would be to use the
play dist command that builds a ZIP archive. Then you only need a Java runtime and database installation on your production server to run your application (everything else is included in the ZIP, including the Scala libraries and a
Another option is to use the
play stage command to run the application in-place. Combine this with a
git push to Heroku or your own production server and you’re ready to go.
Play is build on Netty, which provides very high HTTP server performance. Play supports both synchronous and asynchronous IO, so handling many long-lived connections should be possible (and Play provides excellent support for streaming using its Iteratees based data stream support). Integration with Akka 2.0 should give you all the tools you need to build high-performance and highly-scalable applications.
To give you an idea, I had no trouble getting more than 10.000 HTTP requests per second (tested using jmeter) on my mid-2010 MacBook Pro (2.66 GHz Intel Core i7). The rendered HTML page was fairly trivial (just the user registration form as shown above), but it is good to know basic performance is very good.
This was just a first quick look at Play 2.0, but I’m quite impressed with the ease of learning, development, and deployment. Play 2.0 is a worthy addition to the Typesafe Stack and should give Java and Scala developers a very good platform to build web applications on.