Play 23x Documentation For Scala Developers 23x Unknown
Play 23x Documentation For Scala Developers 23x Unknown
Play 23x Documentation For Scala Developers 23x Unknown
Play 23x Documentation For Scala Developers 23x Unknown
1. Play 23x Documentation For Scala Developers 23x
Unknown download
https://ebookbell.com/product/play-23x-documentation-for-scala-
developers-23x-unknown-44169140
Explore and download more ebooks at ebookbell.com
2. Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Disintegration 2 Novelas 3 Stories A Little Play William Melvin Kelley
https://ebookbell.com/product/disintegration-2-novelas-3-stories-a-
little-play-william-melvin-kelley-125669910
How To Play Waltzing Matilda In 2 Minutes Even If Youve Never Played A
Piano Before Robin Baker Baker
https://ebookbell.com/product/how-to-play-waltzing-matilda-
in-2-minutes-even-if-youve-never-played-a-piano-before-robin-baker-
baker-26626088
123 Money Plan The Three Most Important Steps To Saving And Spending
Smart Karp
https://ebookbell.com/product/123-money-plan-the-three-most-important-
steps-to-saving-and-spending-smart-karp-18480918
Preventions 321 Weight Loss Plan Eat Your Favorite Foods To Cut
Cravings Improve Energy And Lose Weight Bauer
https://ebookbell.com/product/preventions-321-weight-loss-plan-eat-
your-favorite-foods-to-cut-cravings-improve-energy-and-lose-weight-
bauer-11764776
3. Aerostar And The 3 12point Plan Of Vengeance Peter Nelson
https://ebookbell.com/product/aerostar-and-the-3-12point-plan-of-
vengeance-peter-nelson-48939026
Designa Practical Guide To Riba Plan Of Work 2013 Stages 2 And 3 Riba
Stage Guide 1st Edition Tim Bailey
https://ebookbell.com/product/designa-practical-guide-to-riba-plan-of-
work-2013-stages-2-and-3-riba-stage-guide-1st-edition-tim-
bailey-11911926
Winning Ways For Your Mathematical Plays Vol 3 2 Edition Elwyn R
Berlekamp
https://ebookbell.com/product/winning-ways-for-your-mathematical-
plays-vol-3-2-edition-elwyn-r-berlekamp-2309506
Book1greek Alphabetbook214 Alphabets The Metousiotisbook3 Phd
Dissertation Plan 1st Edition Petros Petrakis
https://ebookbell.com/product/book1greek-alphabetbook214-alphabets-
the-metousiotisbook3-phd-dissertation-plan-1st-edition-petros-
petrakis-43535522
Crush Debt Now A 3step Negotiation Strategy To Pay Off Debt And Win
Financial Freedom Fast Personal Finance Wizard Series Book 2 Cromwell
https://ebookbell.com/product/crush-debt-now-a-3step-negotiation-
strategy-to-pay-off-debt-and-win-financial-freedom-fast-personal-
finance-wizard-series-book-2-cromwell-12240492
5. Documentation
Browse versions 2.8.x
Browse APIs Scala Java
Language English
Main
concepts
Advanced topics
You are viewing the documentation for the 2.3.x release series. The latest stable release series is 2.8.x.
Search
Play for Scala developers
The Scala API for Play application developers is available in the play.api package.
The API available directly inside the play package (such as play.mvc ) is
reserved for Java developers. As a Scala developer, look at play.api.mvc .
Main concepts
▾
▾
HTTP programming
Asynchronous HTTP
programming
The template engine
HTTP form submission and
validation
Working with JSON
Working with XML
Handling file upload
Accessing an SQL database
Using the Cache
Calling WebServices
Integrating with Akka
Internationalization
The application Global object
Testing your application
Logging
Handling data streams
reactively
HTTP API
HTTP Filters
Dependency Injection
Extending Play
Search 2.3.x documentat
HTTP programming
Actions, Controllers and Results
HTTP routing
Manipulating results
Session and Flash scopes
Body parsers
Actions composition
Content negotiation
Asynchronous HTTP programming
Handling asynchronous results
Streaming HTTP responses
Comet sockets
WebSockets
The template engine
Templates syntax
Common use cases
Custom format addition
Form submission and validation
Handling form submission
Protecting against CSRF
Custom Validations
Custom Field Constructors
Working with Json
JSON basics
JSON with HTTP
JSON Reads/Writes/Format Combinators
JSON Transformers
JSON Macro Inception
Working with XML
Handling and serving XML requests
Handling file upload
Direct upload and multipart/form-data
Accessing an SQL database
6. Advanced topics
Found an error in this documentation? The source code for this page can be
found here. After reading the documentation guidelines, please feel free to contribute
a pull request. Have questions or advice to share? Go to our community forums to
start a conversation with the community.
Configuring and using JDBC
Using Anorm to access your database
Integrating with other database access libraries
Using the Cache
The Play cache API
Calling WebServices
The Play WS API
Connecting to OpenID services
Accessing resources protected by OAuth
Integrating with Akka
Setting up Actors and scheduling asynchronous tasks
Internationalization
Messages externalisation and i18n
The application Global object
Application global settings
Intercepting requests
Testing your application
Testing with ScalaTest
Writing functional tests with ScalaTest
Testing with specs2
Writing functional tests with specs2
Logging
The Logging API
Handling data streams reactively
Iteratees
Enumerators
Enumeratees
HTTP Architecture
HTTP API
HTTP Filters
Dependency Injection
Controller Injection
Example Projects
Reverse routing
Javascript Routing
Extending Play
Writing Plugins
7. Actions, Controllers and Results
What is an Action?
Most of the requests received by a Play application are handled by an Action .
A play.api.mvc.Action is basically a (play.api.mvc.Request =>
play.api.mvc.Result) function that handles a request and generates a result to be sent to the client.
An action returns a play.api.mvc.Result value, representing the HTTP response to send to the web client.
In this example Ok constructs a 200 OK response containing a text/plain response body.
Building an Action
The play.api.mvc.Action companion object offers several helper methods to construct an Action value.
The first simplest one just takes as argument an expression block returning a Result :
This is the simplest way to create an Action, but we don’t get a reference to the incoming request. It is often
useful to access the HTTP request calling this Action.
So there is another Action builder that takes as an argument a function Request => Result :
It is often useful to mark the request parameter as implicit so it can be implicitly used by other APIs that
need it:
The last way of creating an Action value is to specify an additional BodyParser argument:
Body parsers will be covered later in this manual. For now you just need to know that the other methods of
creating Action values use a default Any content body parser.
Controllers are action generators
A Controller is nothing more than a singleton object that generates Action values.
The simplest use case for defining an action generator is a method with no parameters that returns
an Action value :
val echo = Action { request =>
Ok("Got request [" + request + "]")
}
Action {
Ok("Hello world")
}
Action { request =>
Ok("Got request [" + request + "]")
}
Action { implicit request =>
Ok("Got request [" + request + "]")
}
Action(parse.json) { implicit request =>
Ok("Got request [" + request + "]")
}
8. Of course, the action generator method can have parameters, and these parameters can be captured by
the Action closure:
Simple results
For now we are just interested in simple results: An HTTP result with a status code, a set of HTTP headers and a
body to be sent to the web client.
These results are defined by play.api.mvc.Result :
Of course there are several helpers available to create common results such as the Ok result in the sample
above:
This produces exactly the same result as before.
Here are several examples to create various results:
All of these helpers can be found in the play.api.mvc.Results trait and companion object.
Redirects are simple results too
Redirecting the browser to a new URL is just another kind of simple result. However, these result types don’t take
a response body.
There are several helpers available to create redirect results:
The default is to use a 303 SEE_OTHER response type, but you can also set a more specific status code if you
need one:
package controllers
import play.api.mvc._
object Application extends Controller {
def index = Action {
Ok("It works!")
}
}
def hello(name: String) = Action {
Ok("Hello " + name)
}
def index = Action {
Result(
header = ResponseHeader(200, Map(CONTENT_TYPE -> "text/plain")),
body = Enumerator("Hello world!".getBytes())
)
}
def index = Action {
Ok("Hello world!")
}
val ok = Ok("Hello world!")
val notFound = NotFound
val pageNotFound = NotFound(<h1>Page not found</h1>)
val badRequest = BadRequest(views.html.form(formWithErrors))
val oops = InternalServerError("Oops")
val anyStatus = Status(488)("Strange response type")
def index = Action {
Redirect("/user/home")
}
def index = Action {
Redirect("/user/home", MOVED_PERMANENTLY)
}
9. “TODO” dummy page
You can use an empty Action implementation defined as TODO : the result is a standard ‘Not implemented
yet’ result page:
Next: HTTP Routing
def index(name:String) = TODO
10. HTTP routing
The built-in HTTP router
The router is the component in charge of translating each incoming HTTP request to an Action.
An HTTP request is seen as an event by the MVC framework. This event contains two major pieces of
information:
Routes are defined in the conf/routes file, which is compiled. This means that you’ll see route errors directly
in your browser:
The routes file syntax
conf/routes is the configuration file used by the router. This file lists all of the routes needed by the
application. Each route consists of an HTTP method and URI pattern, both associated with a call to
an Action generator.
Let’s see what a route definition looks like:
Each route starts with the HTTP method, followed by the URI pattern. The last element is the call definition.
You can also add comments to the route file, with the # character.
the request path (e.g. /clients/1542 , /photos/list ), including the query string
the HTTP method (e.g. GET, POST, …).
GET /clients/:id controllers.Clients.show(id: Long)
# Display a client.
GET /clients/:id controllers.Clients.show(id: Long)
11. The HTTP method
The HTTP method can be any of the valid methods supported by HTTP
( GET , POST , PUT , DELETE , HEAD ).
The URI pattern
The URI pattern defines the route’s request path. Parts of the request path can be dynamic.
Static path
For example, to exactly match incoming GET /clients/all requests, you can define this route:
Dynamic parts
If you want to define a route that retrieves a client by ID, you’ll need to add a dynamic part:
Note that a URI pattern may have more than one dynamic part.
The default matching strategy for a dynamic part is defined by the regular expression [^/]+ , meaning that any
dynamic part defined as :id will match exactly one URI part.
Dynamic parts spanning several /
If you want a dynamic part to capture more than one URI path segment, separated by forward slashes, you can
define a dynamic part using the *id syntax, which uses the .+ regular expression:
Here for a request like GET /files/images/logo.png , the name dynamic part will capture
the images/logo.png value.
Dynamic parts with custom regular expressions
You can also define your own regular expression for the dynamic part, using the $id<regex> syntax:
Call to the Action generator method
The last part of a route definition is the call. This part must define a valid call to a method returning
a play.api.mvc.Action value, which will typically be a controller action method.
If the method does not define any parameters, just give the fully-qualified method name:
If the action method defines some parameters, all these parameter values will be searched for in the request URI,
either extracted from the URI path itself, or from the query string.
Or:
GET /clients/all controllers.Clients.list()
GET /clients/:id controllers.Clients.show(id: Long)
GET /files/*name controllers.Application.download(name)
GET /items/$id<[0-9]+> controllers.Items.show(id: Long)
GET / controllers.Application.homePage()
# Extract the page parameter from the path.
GET /:page controllers.Application.show(page)
12. Here is the corresponding, show method definition in the controllers.Application controller:
Parameter types
For parameters of type String , typing the parameter is optional. If you want Play to transform the incoming
parameter into a specific Scala type, you can explicitly type the parameter:
And do the same on the corresponding show method definition in the controllers.Clients controller:
Parameters with fixed values
Sometimes you’ll want to use a fixed value for a parameter:
Parameters with default values
You can also provide a default value that will be used if no value is found in the incoming request:
Optional parameters
You can also specify an optional parameter that does not need to be present in all requests:
Routing priority
Many routes can match the same request. If there is a conflict, the first route (in declaration order) is used.
Reverse routing
The router can also be used to generate a URL from within a Scala call. This makes it possible to centralize all
your URI patterns in a single configuration file, so you can be more confident when refactoring your application.
For each controller used in the routes file, the router will generate a ‘reverse controller’ in the routes package,
having the same action methods, with the same signature, but returning a play.api.mvc.Call instead of
a play.api.mvc.Action .
The play.api.mvc.Call defines an HTTP call, and provides both the HTTP method and the URI.
For example, if you create a controller like:
# Extract the page parameter from the query string.
GET / controllers.Application.show(page)
def show(page: String) = Action {
loadContentFromDatabase(page).map { htmlContent =>
Ok(htmlContent).as("text/html")
}.getOrElse(NotFound)
}
GET /clients/:id controllers.Clients.show(id: Long)
def show(id: Long) = Action {
Client.findById(id).map { client =>
Ok(views.html.Clients.display(client))
}.getOrElse(NotFound)
}
# Extract the page parameter from the path, or fix the value for /
GET / controllers.Application.show(page = "home")
GET /:page controllers.Application.show(page)
# Pagination links, like /clients?page=3
GET /clients controllers.Clients.list(page: Int ?= 1)
# The version parameter is optional. E.g. /api/list-all?version=3.0
GET /api/list-all controllers.Api.list(version: Option[String])
13. And if you map it in the conf/routes file:
You can then reverse the URL to the hello action method, by using
the controllers.routes.Application reverse controller:
Next: Manipulating results
package controllers
import play.api._
import play.api.mvc._
object Application extends Controller {
def hello(name: String) = Action {
Ok("Hello " + name + "!")
}
}
# Hello action
GET /hello/:name controllers.Application.hello(name)
// Redirect to /hello/Bob
def helloBob = Action {
Redirect(routes.Application.hello("Bob"))
}
14. Manipulating Results
Changing the default Content-Type
The result content type is automatically inferred from the Scala value that you specify as the response body.
For example:
Will automatically set the Content-Type header to text/plain , while:
will set the Content-Type header to application/xml .
Tip: this is done via the play.api.http.ContentTypeOf type class.
This is pretty useful, but sometimes you want to change it. Just use the as(newContentType) method on a
result to create a new similar result with a different Content-Type header:
or even better, using:
Note: The benefit of using HTML instead of the "text/html" is that the charset will be automatically handled for you
and the actual Content-Type header will be set to text/html; charset=utf-8 . We will see that in a bit.
Manipulating HTTP headers
You can also add (or update) any HTTP header to the result:
Note that setting an HTTP header will automatically discard the previous value if it was existing in the original
result.
Setting and discarding cookies
Cookies are just a special form of HTTP headers but we provide a set of helpers to make it easier.
You can easily add a Cookie to the HTTP response using:
Also, to discard a Cookie previously stored on the Web browser:
You can also set and remove cookies as part of the same response:
val textResult = Ok("Hello World!")
val xmlResult = Ok(<message>Hello World!</message>)
val htmlResult = Ok(<h1>Hello World!</h1>).as("text/html")
val htmlResult2 = Ok(<h1>Hello World!</h1>).as(HTML)
val result = Ok("Hello World!").withHeaders(
CACHE_CONTROL -> "max-age=3600",
ETAG -> "xx")
val result = Ok("Hello world").withCookies(
Cookie("theme", "blue"))
val result2 = result.discardingCookies(DiscardingCookie("theme"))
15. Changing the charset for text based HTTP responses.
For text based HTTP response it is very important to handle the charset correctly. Play handles that for you and
uses utf-8 by default.
The charset is used to both convert the text response to the corresponding bytes to send over the network
socket, and to update the Content-Type header with the proper ;charset=xxx extension.
The charset is handled automatically via the play.api.mvc.Codec type class. Just import an implicit
instance of play.api.mvc.Codec in the current scope to change the charset that will be used by all
operations:
Here, because there is an implicit charset value in the scope, it will be used by both the Ok(...) method to
convert the XML message into ISO-8859-1 encoded bytes and to generate the text/html;
charset=iso-8859-1 Content-Type header.
Now if you are wondering how the HTML method works, here it is how it is defined:
You can do the same in your API if you need to handle the charset in a generic way.
Next: Session and Flash scopes
val result3 = result.withCookies(Cookie("theme", "blue")).discardingCookies(DiscardingCookie("skin"))
object Application extends Controller {
implicit val myCustomCharset = Codec.javaSupported("iso-8859-1")
def index = Action {
Ok(<h1>Hello World!</h1>).as(HTML)
}
}
def HTML(implicit codec: Codec) = {
"text/html; charset=" + codec.charset
}
16. Session and Flash scopes
How it is different in Play
If you have to keep data across multiple HTTP requests, you can save them in the Session or Flash scopes. Data
stored in the Session are available during the whole user Session, and data stored in the Flash scope are
available to the next request only.
It’s important to understand that Session and Flash data are not stored by the server but are added to each
subsequent HTTP request, using the cookie mechanism. This means that the data size is very limited (up to 4 KB)
and that you can only store string values. The default name for the cookie is PLAY_SESSION . This can be
changed by configuring the key session.cookieName in application.conf.
If the name of the cookie is changed, the earlier cookie can be discarded using the same methods mentioned in Setting and
discarding cookies.
Of course, cookie values are signed with a secret key so the client can’t modify the cookie data (or it will be
invalidated).
The Play Session is not intended to be used as a cache. If you need to cache some data related to a specific
Session, you can use the Play built-in cache mechanism and store a unique ID in the user Session to keep them
related to a specific user.
There is no technical timeout for the Session. It expires when the user closes the web browser. If you need a functional
timeout for a specific application, just store a timestamp into the user Session and use it however your application needs
(e.g. for a maximum session duration, maximum inactivity duration, etc.).
Storing data in the Session
As the Session is just a Cookie, it is also just an HTTP header. You can manipulate the session data the same
way you manipulate other results properties:
Note that this will replace the whole session. If you need to add an element to an existing Session, just add an
element to the incoming session, and specify that as new session:
You can remove any value from the incoming session the same way:
Reading a Session value
You can retrieve the incoming Session from the HTTP request:
Ok("Welcome!").withSession(
"connected" -> "[email protected]")
Ok("Hello World!").withSession(
request.session + ("saidHello" -> "yes"))
Ok("Theme reset!").withSession(
request.session - "theme")
def index = Action { request =>
request.session.get("connected").map { user =>
Ok("Hello " + user)
}.getOrElse {
17. Discarding the whole session
There is special operation that discards the whole session:
Flash scope
The Flash scope works exactly like the Session, but with two differences:
Important: The Flash scope should only be used to transport success/error messages on simple non-Ajax applications. As
the data are just kept for the next request and because there are no guarantees to ensure the request order in a complex
Web application, the Flash scope is subject to race conditions.
Here are a few examples using the Flash scope:
To retrieve the Flash scope value in your view, just add an implicit with Flash:
If the error ‘could not find implicit value for parameter flash: play.api.mvc.Flash’ is raised then this is because your
Action didn’t import a request object. Add an “implicit request=>” as show below:
Next: Body parsers
Unauthorized("Oops, you are not connected")
}
}
Ok("Bye").withNewSession
data are kept for only one request
the Flash cookie is not signed, making it possible for the user to modify it.
def index = Action { implicit request =>
Ok {
request.flash.get("success").getOrElse("Welcome!")
}
}
def save = Action {
Redirect("/home").flashing(
"success" -> "The item has been created")
}
@()(implicit flash: Flash)
...
@flash.get("success").getOrElse("Welcome!")
...
def index() = Action {
implicit request =>
Ok(views.html.Application.index())
}
18. Body parsers
What is a body parser?
An HTTP PUT or POST request contains a body. This body can use any format, specified in the Content-
Type request header. In Play, a body parser transforms this request body into a Scala value.
However the request body for an HTTP request can be very large and a body parser can’t just wait and load the
whole data set into memory before parsing it. A BodyParser[A] is basically
an Iteratee[Array[Byte],A] , meaning that it receives chunks of bytes (as long as the web browser
uploads some data) and computes a value of type A as result.
Let’s consider some examples.
Additionally a body parser has access to the HTTP request headers before it starts parsing the request body,
and has the opportunity to run some precondition checks. For example, a body parser can check that some
HTTP headers are properly set, or that the user trying to upload a large file has the permission to do so.
Note: That’s why a body parser is not really an Iteratee[Array[Byte],A] but more precisely
a Iteratee[Array[Byte],Either[Result,A]] , meaning that it has the opportunity to send directly an HTTP result
itself (typically 400 BAD_REQUEST , 412 PRECONDITION_FAILED or 413 REQUEST_ENTITY_TOO_LARGE ) if it
decides that it is not able to compute a correct value for the request body
Once the body parser finishes its job and gives back a value of type A , the corresponding Action function is
executed and the computed body value is passed into the request.
More about Actions
Previously we said that an Action was a Request => Result function. This is not entirely true. Let’s have
a more precise look at the Action trait:
First we see that there is a generic type A , and then that an action must define a BodyParser[A] .
With Request[A] being defined as:
The A type is the type of the request body. We can use any Scala type as the request body, for
example String , NodeSeq , Array[Byte] , JsonValue , or java.io.File , as long as we have a
body parser able to process it.
To summarize, an Action[A] uses a BodyParser[A] to retrieve a value of type A from the HTTP request,
and to build a Request[A] object that is passed to the action code.
A text body parser could accumulate chunks of bytes into a String, and give the computed String as result
( Iteratee[Array[Byte],String] ).
A file body parser could store each chunk of bytes into a local file, and give a reference to the java.io.File as result
( Iteratee[Array[Byte],File] ).
A s3 body parser could push each chunk of bytes to Amazon S3 and give a the S3 object id as result
( Iteratee[Array[Byte],S3ObjectId] ).
trait Action[A] extends (Request[A] => Result) {
def parser: BodyParser[A]
}
trait Request[+A] extends RequestHeader {
def body: A
}
19. Default body parser: AnyContent
In our previous examples we never specified a body parser. So how can it work? If you don’t specify your own
body parser, Play will use the default, which processes the body as an instance
of play.api.mvc.AnyContent .
This body parser checks the Content-Type header and decides what kind of body to process:
For example:
Specifying a body parser
The body parsers available in Play are defined in play.api.mvc.BodyParsers.parse .
So for example, to define an action expecting a text body (as in the previous example):
Do you see how the code is simpler? This is because the parse.text body parser already sent a 400
BAD_REQUEST response if something went wrong. We don’t have to check again in our action code, and we can
safely assume that request.body contains the valid String body.
Alternatively we can use:
This one doesn’t check the Content-Type header and always loads the request body as a String .
Tip: There is a tolerant fashion provided for all body parsers included in Play.
Here is another example, which will store the request body in a file:
Combining body parsers
text/plain: String
application/json: JsValue
application/xml, text/xml or application/XXX+xml: NodeSeq
application/form-url-encoded: Map[String, Seq[String]]
multipart/form-data: MultipartFormData[TemporaryFile]
any other content type: RawBuffer
def save = Action { request =>
val body: AnyContent = request.body
val textBody: Option[String] = body.asText
// Expecting text body
textBody.map { text =>
Ok("Got: " + text)
}.getOrElse {
BadRequest("Expecting text/plain request body")
}
}
def save = Action(parse.text) { request =>
Ok("Got: " + request.body)
}
def save = Action(parse.tolerantText) { request =>
Ok("Got: " + request.body)
}
def save = Action(parse.file(to = new File("/tmp/upload"))) { request =>
Ok("Saved the request content to " + request.body)
}
20. In the previous example, all request bodies are stored in the same file. This is a bit problematic isn’t it? Let’s write
another custom body parser that extracts the user name from the request Session, to give a unique file for each
user:
Note: Here we are not really writing our own BodyParser, but just combining existing ones. This is often enough and should
cover most use cases. Writing a BodyParser from scratch is covered in the advanced topics section.
Max content length
Text based body parsers (such as text, json, xml or formUrlEncoded) use a maximum content length because
they have to load all of the content into memory.
There is a default maximum content length (the default is 100KB), but you can also specify it inline:
Tip: The default content size can be defined in application.conf :
parsers.text.maxLength=128K
Unit sizes are defined in Size in bytes format section of the Configuration page.
You can also wrap any body parser with maxLength :
Next: Action composition
val storeInUserFile = parse.using { request =>
request.session.get("username").map { user =>
file(to = new File("/tmp/" + user + ".upload"))
}.getOrElse {
sys.error("You don't have the right to upload here")
}
}
def save = Action(storeInUserFile) { request =>
Ok("Saved the request content to " + request.body)
}
// Accept only 10KB of data.
def save = Action(parse.text(maxLength = 1024 * 10)) { request =>
Ok("Got: " + text)
}
// Accept only 10KB of data.
def save = Action(parse.maxLength(1024 * 10, storeInUserFile)) { request =>
Ok("Saved the request content to " + request.body)
}
21. Action composition
This chapter introduces several ways of defining generic action functionality.
Custom action builders
We saw previously that there are multiple ways to declare an action - with a request parameter, without a request
parameter, with a body parser etc. In fact there are more than this, as we’ll see in the chapter on asynchronous
programming.
These methods for building actions are actually all defined by a trait called ActionBuilder , and
the Action object that we use to declare our actions is just an instance of this trait. By implementing your
own ActionBuilder , you can declare reusable action stacks, that can then be used to build actions.
Let’s start with the simple example of a logging decorator, we want to log each call to this action.
The first way is to implement this functionality in the invokeBlock method, which is called for every action
built by the ActionBuilder :
Now we can use it the same way we use Action :
Since ActionBuilder provides all the different methods of building actions, this also works with, for example,
declaring a custom body parser:
Composing actions
In most applications, we will want to have multiple action builders, some that do different types of authentication,
some that provide different types of generic functionality, etc. In which case, we won’t want to rewrite our logging
action code for each type of action builder, we will want to define it in a reuseable way.
Reusable action code can be implemented by wrapping actions:
We can also use the Action action builder to build actions without defining our own action class:
import play.api.mvc._
object LoggingAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
Logger.info("Calling action")
block(request)
}
}
def index = LoggingAction {
Ok("Hello World")
}
def submit = LoggingAction(parse.text) { request =>
Ok("Got a body " + request.body.length + " bytes long")
}
import play.api.mvc._
case class Logging[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Future[Result] = {
Logger.info("Calling action")
action(request)
}
lazy val parser = action.parser
}
import play.api.mvc._
def logging[A](action: Action[A])= Action.async(action.parser) { request =>
Logger.info("Calling action")
action(request)
}
22. Actions can be mixed in to action builders using the composeAction method:
Now the builder can be used in the same way as before:
We can also mix in wrapping actions without the action builder:
More complicated actions
So far we’ve only shown actions that don’t impact the request at all. Of course, we can also read and modify the
incoming request object:
Note: Play already has built in support for X-Forwarded-For headers.
We could block the request:
And finally we can also modify the returned result:
Different request types
While action composition allows you to perform additional processing at the HTTP request and response level,
often you want to build pipelines of data transformations that add context to or perform validation on the request
itself. ActionFunction can be thought of as a function on the request, parameterized over both the input
request type and the output type passed on to the next layer. Each action function may represent modular
processing such as authentication, database lookups for objects, permission checks, or other operations that
you wish to compose and reuse across actions.
There are a few pre-defined traits implementing ActionFunction that are useful for different types of
processing:
object LoggingAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
block(request)
}
override def composeAction[A](action: Action[A]) = new Logging(action)
}
def index = LoggingAction {
Ok("Hello World")
}
def index = Logging {
Action {
Ok("Hello World")
}
}
import play.api.mvc._
def xForwardedFor[A](action: Action[A]) = Action.async(action.parser) { request =>
val newRequest = request.headers.get("X-Forwarded-For").map { xff =>
new WrappedRequest[A](request) {
override def remoteAddress = xff
}
} getOrElse request
action(newRequest)
}
import play.api.mvc._
def onlyHttps[A](action: Action[A]) = Action.async(action.parser) { request =>
request.headers.get("X-Forwarded-Proto").collect {
case "https" => action(request)
} getOrElse {
Future.successful(Forbidden("Only HTTPS requests allowed"))
}
}
import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits._
def addUaHeader[A](action: Action[A]) = Action.async(action.parser) { request =>
action(request).map(_.withHeaders("X-UA-Compatible" -> "Chrome=1"))
}
23. You can also define your own arbitrary ActionFunction by implementing the invokeBlock method. Often
it is convenient to make the input and output types instances of Request (using WrappedRequest ), but this
is not strictly necessary.
Authentication
One of the most common use cases for action functions is authentication. We can easily implement our own
authentication action transformer that determines the user from the original request and adds it to a
new UserRequest . Note that this is also an ActionBuilder because it takes a simple Request as input:
Play also provides a built in authentication action builder. Information on this and how to use it can be found here.
Note: The built in authentication action builder is just a convenience helper to minimise the code necessary to implement
authentication for simple cases, its implementation is very similar to the example above.
If you have more complex requirements than can be met by the built in authentication action, then implementing your own is
not only simple, it is recommended.
Adding information to requests
Now let’s consider a REST API that works with objects of type Item . There may be many routes under
the /item/:itemId path, and each of these need to look up the item. In this case, it may be useful to put this
logic into an action function.
First of all, we’ll create a request object that adds an Item to our UserRequest :
Now we’ll create an action refiner that looks up that item and returns Either an error ( Left ) or a
new ItemRequest ( Right ). Note that this action refiner is defined inside a method that takes the id of the
item:
Validating requests
Finally, we may want an action function that validates whether a request should continue. For example, perhaps
we want to check whether the user from UserAction has permission to access the item from ItemAction ,
and if not return an error:
ActionTransformer can change the request, for example by adding additional information.
ActionFilter can selectively intercept requests, for example to produce errors, without changing the request value.
ActionRefiner is the general case of both of the above.
ActionBuilder is the special case of functions that take Request as input, and thus can build actions.
import play.api.mvc._
class UserRequest[A](val username: Option[String], request: Request[A]) extends WrappedRequest[A](request)
object UserAction extends
ActionBuilder[UserRequest] with ActionTransformer[Request, UserRequest] {
def transform[A](request: Request[A]) = Future.successful {
new UserRequest(request.session.get("username"), request)
}
}
import play.api.mvc._
class ItemRequest[A](val item: Item, request: UserRequest[A]) extends WrappedRequest[A](request) {
def username = request.username
}
def ItemAction(itemId: String) = new ActionRefiner[UserRequest, ItemRequest] {
def refine[A](input: UserRequest[A]) = Future.successful {
ItemDao.findById(itemId)
.map(new ItemRequest(_, input))
.toRight(NotFound)
}
}
object PermissionCheckAction extends ActionFilter[ItemRequest] {
def filter[A](input: ItemRequest[A]) = Future.successful {
if (!input.item.accessibleByUser(input.username))
Some(Forbidden)
else
None
}
}
24. Putting it all together
Now we can chain these action functions together (starting with an ActionBuilder ) using andThen to
create an action:
Play also provides a global filter API , which is useful for global cross cutting concerns.
Next: Content negotiation
def tagItem(itemId: String, tag: String) =
(UserAction andThen ItemAction(itemId) andThen PermissionCheckAction) { request =>
request.item.addTag(tag)
Ok("User " + request.username + " tagged " + request.item.id)
}
25. Content negotiation
Content negotiation is a mechanism that makes it possible to serve different representation of a same resource
(URI). It is useful e.g. for writing Web Services supporting several output formats (XML, JSON, etc.). Server-driven
negotiation is essentially performed using the Accept* requests headers. You can find more information on
content negotiation in the HTTP specification.
Language
You can get the list of acceptable languages for a request using
the play.api.mvc.RequestHeader#acceptLanguages method that retrieves them from the Accept-
Language header and sorts them according to their quality value. Play uses it in
the play.api.mvc.Controller#lang method that provides an implicit play.api.i18n.Lang value to
your actions, so they automatically use the best possible language (if supported by your application, otherwise
your application’s default language is used).
Content
Similarly, the play.api.mvc.RequestHeader#acceptedTypes method gives the list of acceptable result’s
MIME types for a request. It retrieves them from the Accept request header and sorts them according to their
quality factor.
Actually, the Accept header does not really contain MIME types but media ranges (*e.g.* a request accepting
all text results may set the text/* range, and the */* range means that all result types are acceptable).
Controllers provide a higher-level render method to help you to handle media ranges. Consider for example
the following action definition:
Accepts.Html() and Accepts.Json() are extractors testing if a given media range
matches text/html and application/json , respectively. The render method takes a partial function
from play.api.http.MediaRange to play.api.mvc.Result and tries to apply it to each media range
found in the request Accept header, in order of preference. If none of the acceptable media ranges is
supported by your function, the NotAcceptable result is returned.
For example, if a client makes a request with the following value for
the Accept header: */*;q=0.5,application/json , meaning that it accepts any result type but prefers
JSON, the above code will return the JSON representation. If another client makes a request with the following
value for the Accept header: application/xml , meaning that it only accepts XML, the above code will
return NotAcceptable .
Request extractors
See the API documentation of the play.api.mvc.AcceptExtractors.Accepts object for the list of the
MIME types supported by Play out of the box in the render method. You can easily create your own extractor
for a given MIME type using the play.api.mvc.Accepting case class, for example the following code
creates an extractor checking that a media range matches the audio/mp3 MIME type:
val list = Action { implicit request =>
val items = Item.findAll
render {
case Accepts.Html() => Ok(views.html.list(items))
case Accepts.Json() => Ok(Json.toJson(items))
}
}
val AcceptsMp3 = Accepting("audio/mp3")
render {
case AcceptsMp3() => ???
}
}
27. Handling asynchronous results
Make controllers asynchronous
Internally, Play Framework is asynchronous from the bottom up. Play handles every request in an asynchronous,
non-blocking way.
The default configuration is tuned for asynchronous controllers. In other words, the application code should avoid
blocking in controllers, i.e., having the controller code wait for an operation. Common examples of such blocking
operations are JDBC calls, streaming API, HTTP requests and long computations.
Although it’s possible to increase the number of threads in the default execution context to allow more concurrent
requests to be processed by blocking controllers, following the recommended approach of keeping the
controllers asynchronous makes it easier to scale and to keep the system responsive under load.
Creating non-blocking actions
Because of the way Play works, action code must be as fast as possible, i.e., non-blocking. So what should we
return as result if we are not yet able to generate it? The response is a future result!
A Future[Result] will eventually be redeemed with a value of type Result . By giving
a Future[Result] instead of a normal Result , we are able to quickly generate the result without blocking.
Play will then serve the result as soon as the promise is redeemed.
The web client will be blocked while waiting for the response, but nothing will be blocked on the server, and
server resources can be used to serve other clients.
How to create a Future[Result]
To create a Future[Result] we need another future first: the future that will give us the actual value we need
to compute the result:
All of Play’s asynchronous API calls give you a Future . This is the case whether you are calling an external
web service using the play.api.libs.WS API, or using Akka to schedule asynchronous tasks or to
communicate with actors using play.api.libs.Akka .
Here is a simple way to execute a block of code asynchronously and to get a Future :
Note: It’s important to understand which thread code runs on with futures. In the two code blocks above, there is an import
on Plays default execution context. This is an implicit parameter that gets passed to all methods on the future API that accept
callbacks. The execution context will often be equivalent to a thread pool, though not necessarily.
import play.api.libs.concurrent.Execution.Implicits.defaultContext
val futurePIValue: Future[Double] = computePIAsynchronously()
val futureResult: Future[Result] = futurePIValue.map { pi =>
Ok("PI value computed: " + pi)
}
import play.api.libs.concurrent.Execution.Implicits.defaultContext
val futureInt: Future[Int] = scala.concurrent.Future {
intensiveComputation()
}
28. You can’t magically turn synchronous IO into asynchronous by wrapping it in a Future . If you can’t change the
application’s architecture to avoid blocking operations, at some point that operation will have to be executed, and that thread
is going to block. So in addition to enclosing the operation in a Future , it’s necessary to configure it to run in a separate
execution context that has been configured with enough threads to deal with the expected concurrency. See Understanding
Play thread pools for more information.
It can also be helpful to use Actors for blocking operations. Actors provide a clean model for handling timeouts and failures,
setting up blocking execution contexts, and managing any state that may be associated with the service. Also Actors provide
patterns like ScatterGatherFirstCompletedRouter to address simultaneous cache and database requests and allow
remote execution on a cluster of backend servers. But an Actor may be overkill depending on what you need.
Returning futures
While we were using the Action.apply builder method to build actions until now, to send an asynchronous
result we need to use the Action.async builder method:
Actions are asynchronous by default
Play actions are asynchronous by default. For instance, in the controller code below, the { Ok(...) } part of
the code is not the method body of the controller. It is an anonymous function that is being passed to
the Action object’s apply method, which creates an object of type Action . Internally, the anonymous
function that you wrote will be called and its result will be enclosed in a Future .
Note: Both Action.apply and Action.async create Action objects that are handled internally in the same way.
There is a single kind of Action , which is asynchronous, and not two kinds (a synchronous one and an asynchronous one).
The .async builder is just a facility to simplify creating actions based on APIs that return a Future , which makes it
easier to write non-blocking code.
Handling time-outs
It is often useful to handle time-outs properly, to avoid having the web browser block and wait if something goes
wrong. You can easily compose a promise with a promise timeout to handle these cases:
Next: Streaming HTTP responses
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def index = Action.async {
val futureInt = scala.concurrent.Future { intensiveComputation() }
futureInt.map(i => Ok("Got result: " + i))
}
val echo = Action { request =>
Ok("Got request [" + request + "]")
}
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.duration._
def index = Action.async {
val futureInt = scala.concurrent.Future { intensiveComputation() }
val timeoutFuture = play.api.libs.concurrent.Promise.timeout("Oops", 1.second)
Future.firstCompletedOf(Seq(futureInt, timeoutFuture)).map {
case i: Int => Ok("Got result: " + i)
case t: String => InternalServerError(t)
}
}
29. Streaming HTTP responses
Standard responses and Content-Length header
Since HTTP 1.1, to keep a single connection open to serve several HTTP requests and responses, the server
must send the appropriate Content-Length HTTP header along with the response.
By default, you are not specifying a Content-Length header when you send back a simple result, such as:
Of course, because the content you are sending is well-known, Play is able to compute the content size for you
and to generate the appropriate header.
Note that for text-based content it is not as simple as it looks, since the Content-Length header must be computed
according the character encoding used to translate characters to bytes.
Actually, we previously saw that the response body is specified using
a play.api.libs.iteratee.Enumerator :
This means that to compute the Content-Length header properly, Play must consume the whole enumerator
and load its content into memory.
Sending large amounts of data
If it’s not a problem to load the whole content into memory for simple Enumerators, what about large data sets?
Let’s say we want to return a large file to the web client.
Let’s first see how to create an Enumerator[Array[Byte]] enumerating the file content:
Now it looks simple right? Let’s just use this enumerator to specify the response body:
Actually we have a problem here. As we don’t specify the Content-Length header, Play will have to compute
it itself, and the only way to do this is to consume the whole enumerator content and load it into memory, and
then compute the response size.
That’s a problem for large files that we don’t want to load completely into memory. So to avoid that, we just have
to specify the Content-Length header ourself.
def index = Action {
Ok("Hello World")
}
def index = Action {
Result(
header = ResponseHeader(200),
body = Enumerator("Hello World")
)
}
val file = new java.io.File("/tmp/fileToServe.pdf")
val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file)
def index = Action {
val file = new java.io.File("/tmp/fileToServe.pdf")
val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file)
Result(
header = ResponseHeader(200),
body = fileContent
)
}
30. This way Play will consume the body enumerator in a lazy way, copying each chunk of data to the HTTP
response as soon as it is available.
Serving files
Of course, Play provides easy-to-use helpers for common task of serving a local file:
This helper will also compute the Content-Type header from the file name, and add the Content-
Disposition header to specify how the web browser should handle this response. The default is to ask the
web browser to download this file by adding the header Content-Disposition: attachment;
filename=fileToServe.pdf to the HTTP response.
You can also provide your own file name:
If you want to serve this file inline :
Now you don’t have to specify a file name since the web browser will not try to download it, but will just display
the file content in the web browser window. This is useful for content types supported natively by the web
browser, such as text, HTML or images.
Chunked responses
For now, it works well with streaming file content since we are able to compute the content length before
streaming it. But what about dynamically computed content, with no content size available?
For this kind of response we have to use Chunked transfer encoding.
Chunked transfer encoding is a data transfer mechanism in version 1.1 of the Hypertext Transfer Protocol (HTTP) in which a
web server serves content in a series of chunks. It uses the Transfer-Encoding HTTP response header instead of
the Content-Length header, which the protocol would otherwise require. Because the Content-Length header is not
used, the server does not need to know the length of the content before it starts transmitting a response to the client (usually
a web browser). Web servers can begin transmitting responses with dynamically-generated content before knowing the total
size of that content.
The size of each chunk is sent right before the chunk itself, so that a client can tell when it has finished receiving data for that
chunk. Data transfer is terminated by a final chunk of length zero.
http://en.wikipedia.org/wiki/Chunked_transfer_encoding
def index = Action {
val file = new java.io.File("/tmp/fileToServe.pdf")
val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file)
Result(
header = ResponseHeader(200, Map(CONTENT_LENGTH -> file.length.toString)),
body = fileContent
)
}
def index = Action {
Ok.sendFile(new java.io.File("/tmp/fileToServe.pdf"))
}
def index = Action {
Ok.sendFile(
content = new java.io.File("/tmp/fileToServe.pdf"),
fileName = _ => "termsOfService.pdf"
)
}
def index = Action {
Ok.sendFile(
content = new java.io.File("/tmp/fileToServe.pdf"),
inline = true
)
}
31. The advantage is that we can serve the data live, meaning that we send chunks of data as soon as they are
available. The drawback is that since the web browser doesn’t know the content size, it is not able to display a
proper download progress bar.
Let’s say that we have a service somewhere that provides a dynamic InputStream computing some data.
First we have to create an Enumerator for this stream:
We can now stream these data using a ChunkedResult :
As always, there are helpers available to do this:
Of course, we can use any Enumerator to specify the chunked data:
We can inspect the HTTP response sent by the server:
We get three chunks followed by one final empty chunk that closes the response.
Next: Comet sockets
val data = getDataStream
val dataContent: Enumerator[Array[Byte]] = Enumerator.fromStream(data)
def index = Action {
val data = getDataStream
val dataContent: Enumerator[Array[Byte]] = Enumerator.fromStream(data)
ChunkedResult(
header = ResponseHeader(200),
chunks = dataContent
)
}
def index = Action {
val data = getDataStream
val dataContent: Enumerator[Array[Byte]] = Enumerator.fromStream(data)
Ok.chunked(dataContent)
}
def index = Action {
Ok.chunked(
Enumerator("kiki", "foo", "bar").andThen(Enumerator.eof)
)
}
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
4
kiki
3
foo
3
bar
0
32. Comet sockets
Using chunked responses to create Comet sockets
A good use for Chunked responses is to create Comet sockets. A Comet socket is just a
chunked text/html response containing only <script> elements. At each chunk we write
a <script> tag that is immediately executed by the web browser. This way we can send events live to the web
browser from the server: for each message, wrap it into a <script> tag that calls a JavaScript callback
function, and writes it to the chunked response.
Let’s write a first proof-of-concept: an enumerator that generates <script> tags that each call the
browser console.log JavaScript function:
If you run this action from a web browser, you will see the three events logged in the browser console.
We can write this in a better way by using play.api.libs.iteratee.Enumeratee that is just an adapter to
transform an Enumerator[A] into another Enumerator[B] . Let’s use it to wrap standard messages into
the <script> tags:
Tip: Writing events &> toCometMessage is just another way of writing events.through(toCometMessage)
Using the play.api.libs.Comet helper
We provide a Comet helper to handle these Comet chunked streams that do almost the same stuff that we just
wrote.
Note: Actually it does more, like pushing an initial blank buffer data for browser compatibility, and it supports both String and
JSON messages. It can also be extended via type classes to support more message types.
Let’s just rewrite the previous example to use it:
def comet = Action {
val events = Enumerator(
"""<script>console.log('kiki')</script>""",
"""<script>console.log('foo')</script>""",
"""<script>console.log('bar')</script>"""
)
Ok.chunked(events).as(HTML)
}
import play.twirl.api.Html
// Transform a String message into an Html script tag
val toCometMessage = Enumeratee.map[String] { data =>
Html("""<script>console.log('""" + data + """')</script>""")
}
def comet = Action {
val events = Enumerator("kiki", "foo", "bar")
Ok.chunked(events &> toCometMessage)
}
def comet = Action {
val events = Enumerator("kiki", "foo", "bar")
Ok.chunked(events &> Comet(callback = "console.log"))
}
33. The forever iframe technique
The standard technique to write a Comet socket is to load an infinite chunked comet response in an
HTML iframe and to specify a callback calling the parent frame:
With an HTML page like:
Next: WebSockets
def comet = Action {
val events = Enumerator("kiki", "foo", "bar")
Ok.chunked(events &> Comet(callback = "parent.cometMessage"))
}
<script type="text/javascript">
var cometMessage = function(event) {
console.log('Received event: ' + event)
}
</script>
<iframe src="/comet"></iframe>
34. WebSockets
WebSockets are sockets that can be used from a web browser based on a protocol that allows two way full
duplex communication. The client can send messages and the server can receive messages at any time, as long
as there is an active WebSocket connection between the server and the client.
Modern HTML5 compliant web browsers natively support WebSockets via a JavaScript WebSocket API.
However WebSockets are not limited in just being used by WebBrowsers, there are many WebSocket client
libraries available, allowing for example servers to talk to each other, and also native mobile apps to use
WebSockets. Using WebSockets in these contexts has the advantage of being able to reuse the existing TCP
port that a Play server uses.
Handling WebSockets
Until now, we were using Action instances to handle standard HTTP requests and send back standard HTTP
responses. WebSockets are a totally different beast and can’t be handled via standard Action .
Play provides two different built in mechanisms for handling WebSockets. The first is using actors, the second is
using iteratees. Both of these mechanisms can be accessed using the builders provided on WebSocket.
Handling WebSockets with actors
To handle a WebSocket with an actor, we need to give Play a akka.actor.Props object that describes the
actor that Play should create when it receives the WebSocket connection. Play will give us
an akka.actor.ActorRef to send upstream messages to, so we can use that to help create
the Props object:
The actor that we’re sending to here in this case looks like this:
Any messages received from the client will be sent to the actor, and any messages sent to the actor supplied by
Play will be sent to the client. The actor above simply sends every message received from the client back with I
received your message: prepended to it.
Detecting when a WebSocket has closed
When the WebSocket has closed, Play will automatically stop the actor. This means you can handle this situation
by implementing the actors postStop method, to clean up any resources the WebSocket might have
consumed. For example:
import play.api.mvc._
import play.api.Play.current
def socket = WebSocket.acceptWithActor[String, String] { request => out =>
MyWebSocketActor.props(out)
}
import akka.actor._
object MyWebSocketActor {
def props(out: ActorRef) = Props(new MyWebSocketActor(out))
}
class MyWebSocketActor(out: ActorRef) extends Actor {
def receive = {
case msg: String =>
out ! ("I received your message: " + msg)
}
}
override def postStop() = {
someResource.close()
}
35. Closing a WebSocket
Play will automatically close the WebSocket when your actor that handles the WebSocket terminates. So, to
close the WebSocket, send a PoisonPill to your own actor:
Rejecting a WebSocket
Sometimes you may wish to reject a WebSocket request, for example, if the user must be authenticated to
connect to the WebSocket, or if the WebSocket is associated with some resource, whose id is passed in the
path, but no resource with that id exists. Play provides tryAcceptWithActor to address this, allowing you to
return either a result (such as forbidden, or not found), or the actor to handle the WebSocket with:
Handling different types of messages
So far we have only seen handling String frames. Play also has built in handlers for Array[Byte] frames,
and JsValue messages parsed from String frames. You can pass these as the type parameters to the
WebSocket creation method, for example:
You may have noticed that there are two type parameters, this allows us to handle differently typed messages
coming in to messages going out. This is typically not useful with the lower level frame types, but can be useful if
you parse the messages into a higher level type.
For example, let’s say we want to receive JSON messages, and we want to parse incoming messages
as InEvent and format outgoing messages as OutEvent . The first thing we want to do is create JSON
formats for out InEvent and OutEvent types:
Now we can create WebSocket FrameFormatter ’s for these types:
And finally, we can use these in our WebSocket:
Now in our actor, we will receive messages of type InEvent , and we can send messages of type OutEvent .
Handling WebSockets with iteratees
import akka.actor.PoisonPill
self ! PoisonPill
import scala.concurrent.Future
import play.api.mvc._
import play.api.Play.current
def socket = WebSocket.tryAcceptWithActor[String, String] { request =>
Future.successful(request.session.get("user") match {
case None => Left(Forbidden)
case Some(_) => Right(MyWebSocketActor.props)
})
}
import play.api.mvc._
import play.api.libs.json._
import play.api.Play.current
def socket = WebSocket.acceptWithActor[JsValue, JsValue] { request => out =>
MyWebSocketActor.props(out)
}
import play.api.libs.json._
implicit val inEventFormat = Json.format[InEvent]
implicit val outEventFormat = Json.format[OutEvent]
import play.api.mvc.WebSocket.FrameFormatter
implicit val inEventFrameFormatter = FrameFormatter.jsonFrame[InEvent]
implicit val outEventFrameFormatter = FrameFormatter.jsonFrame[OutEvent]
import play.api.mvc._
import play.api.Play.current
def socket = WebSocket.acceptWithActor[InEvent, OutEvent] { request => out =>
MyWebSocketActor.props(out)
}
36. While actors are a better abstraction for handling discrete messages, iteratees are often a better abstraction for
handling streams.
To handle a WebSocket request, use a WebSocket instead of an Action :
A WebSocket has access to the request headers (from the HTTP request that initiates the WebSocket
connection), allowing you to retrieve standard headers and session data. However, it doesn’t have access to a
request body, nor to the HTTP response.
When constructing a WebSocket this way, we must return both in and out channels.
It this example we are creating a simple iteratee that prints each message to console. To send messages, we
create a simple dummy enumerator that will send a single Hello! message.
Tip: You can test WebSockets on http://websocket.org/echo.html. Just set the location to ws://localhost:9000 .
Let’s write another example that discards the input data and closes the socket just after sending
the Hello! message:
Here is another example in which the input data is logged to standard out and broadcast by to the client utilizing
‘Concurrent.broadcast’.
Next: The template engine
import play.api.mvc._
import play.api.libs.iteratee._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def socket = WebSocket.using[String] { request =>
// Log events to the console
val in = Iteratee.foreach[String](println).map { _ =>
println("Disconnected")
}
// Send a single 'Hello!' message
val out = Enumerator("Hello!")
(in, out)
}
The in channel is an Iteratee[A,Unit] (where A is the message type - here we are using String ) that will be
notified for each message, and will receive EOF when the socket is closed on the client side.
The out channel is an Enumerator[A] that will generate the messages to be sent to the Web client. It can close the
connection on the server side by sending EOF .
import play.api.mvc._
import play.api.libs.iteratee._
def socket = WebSocket.using[String] { request =>
// Just ignore the input
val in = Iteratee.ignore[String]
// Send a single 'Hello!' message and close
val out = Enumerator("Hello!").andThen(Enumerator.eof)
(in, out)
}
import play.api.mvc._
import play.api.libs.iteratee._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def socket = WebSocket.using[String] { request =>
// Concurrent.broadcast returns (Enumerator, Concurrent.Channel)
val (out, channel) = Concurrent.broadcast[String]
// log the message to stdout and send response back to client
val in = Iteratee.foreach[String] {
msg => println(msg)
// the Enumerator returned by Concurrent.broadcast subscribes to the channel and will
// receive the pushed messages
channel push("I received your message: " + msg)
}
(in,out)
}
37. The template engine
A type safe template engine based on Scala
Play comes with Twirl, a powerful Scala-based template engine, whose design was inspired by ASP.NET Razor.
Specifically it is:
Templates are compiled, so you will see any errors in your browser:
Overview
A Play Scala template is a simple text file that contains small blocks of Scala code. Templates can generate any
text-based format, such as HTML, XML or CSV.
The template system has been designed to feel comfortable to those used to working with HTML, allowing front-
end developers to easily work with the templates.
Templates are compiled as standard Scala functions, following a simple naming convention. If you create
a views/Application/index.scala.html template file, it will generate
a views.html.Application.index class that has an apply() method.
compact, expressive, and fluid: it minimizes the number of characters and keystrokes required in a file, and enables a
fast, fluid coding workflow. Unlike most template syntaxes, you do not need to interrupt your coding to explicitly denote
server blocks within your HTML. The parser is smart enough to infer this from your code. This enables a really compact and
expressive syntax which is clean, fast and fun to type.
easy to learn: it allows you to quickly become productive, with a minimum of concepts. You use simple Scala constructs
and all your existing HTML skills.
not a new language: we consciously chose not to create a new language. Instead we wanted to enable Scala developers
to use their existing Scala language skills, and deliver a template markup syntax that enables an awesome HTML
construction workflow.
editable in any text editor: it doesn’t require a specific tool and enables you to be productive in any plain old text editor.
38. For example, here is a simple template:
You can then call this from any Scala code as you would normally call a method on a class:
Syntax: the magic ‘@’ character
The Scala template uses @ as the single special character. Every time this character is encountered, it indicates
the beginning of a dynamic statement. You are not required to explicitly close the code block - the end of the
dynamic statement will be inferred from your code:
Because the template engine automatically detects the end of your code block by analysing your code, this
syntax only supports simple statements. If you want to insert a multi-token statement, explicitly mark it using
brackets:
You can also use curly brackets, to write a multi-statement block:
Because @ is a special character, you’ll sometimes need to escape it. Do this by using @@ :
Template parameters
A template is like a function, so it needs parameters, which must be declared at the top of the template file:
You can also use default values for parameters:
Or even several parameter groups:
Iterating
You can use the for keyword, in a pretty standard way:
@(customer: Customer, orders: List[Order])
<h1>Welcome @customer.name!</h1>
<ul>
@for(order <- orders) {
<li>@order.title</li>
}
</ul>
val content = views.html.Application.index(c, o)
Hello @customer.name!
^^^^^^^^^^^^^
Dynamic code
Hello @(customer.firstName + customer.lastName)!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dynamic Code
Hello @{val name = customer.firstName + customer.lastName; name}!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dynamic Code
My email is bob@@example.com
@(customer: Customer, orders: List[Order])
@(title: String = "Home")
@(title: String)(body: Html)
<ul>
@for(p <- products) {
39. Note: Make sure that { is on the same line with for to indicate that the expression continues to next line.
If-blocks
If-blocks are nothing special. Simply use Scala’s standard if statement:
Declaring reusable blocks
You can create reusable code blocks:
Note that you can also declare reusable pure code blocks:
Note: Declaring code block this way in a template can be sometime useful but keep in mind that a template is not the best
place to write complex logic. It is often better to externalize these kind of code in a Scala class (that you can store under
the views/ package as well if you want).
By convention a reusable block defined with a name starting with implicit will be marked as implicit :
Declaring reusable values
You can define scoped values using the defining helper:
Import statements
You can import whatever you want at the beginning of your template (or sub-template):
<li>@p.name ([email protected])</li>
}
</ul>
@if(items.isEmpty) {
<h1>Nothing to display</h1>
} else {
<h1>@items.size items!</h1>
}
@display(product: Product) = {
@product.name ([email protected])
}
<ul>
@for(product <- products) {
@display(product)
}
</ul>
@title(text: String) = @{
text.split(' ').map(_.capitalize).mkString(" ")
}
<h1>@title("hello world")</h1>
@implicitFieldConstructor = @{ MyFieldConstructor() }
@defining(user.firstName + " " + user.lastName) { fullName =>
<div>Hello @fullName</div>
}
40. To make an absolute resolution, use root prefix in the import statement.
If you have common imports, which you need in all templates, you can declare in build.sbt
Comments
You can write server side block comments in templates using @* *@ :
You can put a comment on the first line to document your template into the Scala API doc:
Escaping
By default, dynamic content parts are escaped according to the template type’s (e.g. HTML or XML) rules. If you
want to output a raw content fragment, wrap it in the template content type.
For example to output raw HTML:
Next: Common use cases
@(customer: Customer, orders: List[Order])
@import utils._
...
@import _root_.company.product.core._
TwirlKeys.templateImports += "org.abc.backend._"
@*********************
* This is a comment *
*********************@
@*************************************
* Home page. *
* *
* @param msg The message to display *
*************************************@
@(msg: String)
<h1>@msg</h1>
<p>
@Html(article.content)
</p>
41. Scala templates common use cases
Templates, being simple functions, can be composed in any way you want. Below are examples of some
common scenarios.
Layout
Let’s declare a views/main.scala.html template that will act as a main layout template:
As you can see, this template takes two parameters: a title and an HTML content block. Now we can use it from
another views/Application/index.scala.html template:
Note: We sometimes use named parameters(like @main(title = "Home") , sometimes not like @main("Home") . It is
as you want, choose whatever is clearer in a specific context.
Sometimes you need a second page-specific content block for a sidebar or breadcrumb trail, for example. You
can do this with an additional parameter:
Using this from our ‘index’ template, we have:
Alternatively, we can declare the sidebar block separately:
@(title: String)(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
</head>
<body>
<section class="content">@content</section>
</body>
</html>
@main(title = "Home") {
<h1>Home page</h1>
}
@(title: String)(sidebar: Html)(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
</head>
<body>
<section class="sidebar">@sidebar</section>
<section class="content">@content</section>
</body>
</html>
@main("Home") {
<h1>Sidebar</h1>
} {
<h1>Home page</h1>
}
@sidebar = {
<h1>Sidebar</h1>
}
@main("Home")(sidebar) {
<h1>Home page</h1>
}
42. Tags (they are just functions, right?)
Let’s write a simple views/tags/notice.scala.html tag that displays an HTML notice:
And now let’s use it from another template:
Includes
Again, there’s nothing special here. You can just call any other template you like (and in fact any other function
coming from anywhere at all):
moreScripts and moreStyles equivalents
To define old moreScripts or moreStyles variables equivalents (like on Play! 1.x) on a Scala template, you can
define a variable in the main template like this :
@(level: String = "error")(body: (String) => Html)
@level match {
case "success" => {
<p class="success">
@body("green")
</p>
}
case "warning" => {
<p class="warning">
@body("orange")
</p>
}
case "error" => {
<p class="error">
@body("red")
</p>
}
}
@import tags._
@notice("error") { color =>
Oops, something is <span style="color:@color">wrong</span>
}
<h1>Home</h1>
<div id="side">
@common.sideBar()
</div>
@(title: String, scripts: Html = Html(""))(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
<link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
<link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
<script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
@scripts
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="#">Movies</a>
</div>
43. And on an extended template that need an extra script :
And on an extended template that not need an extra script, just like this :
Next: Custom format
</div>
</div>
<div class="container">
@content
</div>
</body>
</html>
@scripts = {
<script type="text/javascript">alert("hello !");</script>
}
@main("Title",scripts){
Html content here ...
}
@main("Title"){
Html content here ...
}
44. Adding support for a custom format to the template engine
The built-in template engine supports common template formats (HTML, XML, etc.) but you can easily add
support for your own formats, if needed. This page summarizes the steps to follow to support a custom format.
Overview of the templating process
The template engine builds its result by appending static and dynamic content parts of a template. Consider for
instance the following template:
It consists in two static parts ( foo and baz ) around one dynamic part ( bar ). The template engine
concatenates these parts together to build its result. Actually, in order to prevent cross-site scripting attacks, the
value of bar can be escaped before being concatenated to the rest of the result. This escaping process is
specific to each format: e.g. in the case of HTML you want to transform “<” into “&lt;” .
How does the template engine know which format correspond to a template file? It looks at its extension: e.g. if it
ends with .scala.html it associates the HTML format to the file.
Finally, you usually want your template files to be used as the body of your HTTP responses, so you have to
define how to make a Play result from a template rendering result.
In summary, to support your own template format you need to perform the following steps:
Implement a format
Implement the play.twirl.api.Format[A] trait that has the members:
- raw(text: String): A
- escape(text: String): A
- val empty: Html
- def fill(elements: immutable.Seq[Html]): Html
that will be used to integrate static and dynamic template parts, respectively.
The type parameter A of the format defines the result type of the template rendering, e.g. Html for a HTML
template. This type must be a subtype of the play.twirl.api.Appendable[A] trait that defines how to
concatenate parts together.
For convenience, Play provides a play.twirl.api.BufferedContent[A] abstract class that
implements play.twirl.api.Appendable[A] using a list of A together with a StringBuilder to build
its result and that implements the play.twirl.api.Content trait so Play knows how to serialize it as an
HTTP response body (see the last section of this page for details).
In short, you need to write two classes: one defining the result
(implementing play.twirl.api.Appendable[A] ) and one defining the text integration process
(implementing play.twirl.api.Format[A] ). For instance, here is how the HTML format is defined:
foo @bar baz
Implement the text integration process for the format;
Associate a file extension to the format;
Eventually tell Play how to send the result of a template rendering as an HTTP response body.
// The `Html` result type. We extend `BufferedContent[Html]`
// rather than just `Appendable[Html]` so
// Play knows how to make an HTTP result from a `Html` value
class Html(elements: immutable.Seq[Html], text: String) extends BufferedContent[Html](elements, text) {
val contentType = MimeTypes.HTML
}
object HtmlFormat extends Format[Html] {
45. Associate a file extension to the format
The templates are compiled into a .scala files by the build process just before compiling the whole
application’s sources. The TwirlKeys.templateFormats key is a sbt setting of type Map[String,
String] defining the mapping between file extensions and template formats. For instance, if HTML was not
supported out of the box by Play, you would have to write the following in your build file to associate
the .scala.html files to the play.twirl.api.HtmlFormat format:
Note that the right side of the arrow contains the fully qualified name of a value of
type play.twirl.api.Format[_] .
Tell Play how to make an HTTP result from a template result type
Play can write an HTTP response body for any value of type A for which it exists an
implicit play.api.http.Writeable[A] value. So all you need is to define such a value for your template
result type. For instance, here is how to define such a value for HTTP:
Note: if your template result type extends play.twirl.api.BufferedContent you only need to define an
implicit play.api.http.ContentTypeOf value:
Next: HTTP form submission and validation
def raw(text: String): Html = …
def escape(text: String): Html = …
val empty: Html = …
def fill(elements: immutable.Seq[Html]): Html = …
}
TwirlKeys.templateFormats += ("html" -> "my.HtmlFormat.instance")
§
implicit def writableHttp(implicit codec: Codec): Writeable[Http] =
Writeable[Http](result => codec.encode(result.body), Some(ContentTypes.HTTP))
implicit def contentTypeHttp(implicit codec: Codec): ContentTypeOf[Http] =
ContentTypeOf[Http](Some(ContentTypes.HTTP))
46. Handling form submission
Overview
Form handling and submission is an important part of any web application. Play comes with features that make
handling simple forms easy and complex forms possible.
Play’s form handling approach is based around the concept of binding data. When data comes in from a POST
request, Play will look for formatted values and bind them to a Form object. From there, Play can use the
bound form to value a case class with data, call custom validations, and so on.
Typically forms are used directly from a Controller instance. However, Form definitions do not have to
match up exactly with case classes or models: they are purely for handling input and it is reasonable to use a
distinct Form for a distinct POST.
Imports
To use forms, import the following packages into your class:
To make use of validation and constraints, import the following packages into your class:
Form Basics
We’ll go through the basics of form handling:
The end result will look something like this:
§
import play.api.data._
import play.api.data.Forms._
import play.api.data.validation.Constraints._
defining a form,
defining constraints in the form,
validating the form in an action,
displaying the form in a view template,
and finally, processing the result (or errors) of the form in a view template.
47. Defining a form
First, define a case class which contains the elements you want in the form. Here we want to capture the name
and age of a user, so we create a UserData object:
Now that we have a case class, the next step is to define a Form structure.
The function of a Form is to transform form data into a bound instance of a case class, and we define it like
follows:
The Forms object defines the mapping method. This method takes the names and constraints of the form, and
also takes two functions: an apply function and an unapply function. Because UserData is a case class, we
can plug its apply and unapply methods directly into the mapping method.
Note: Maximum number of fields for a single tuple or mapping is 18 due to the way form handling is implemented. If you
have more than 18 fields in your form, you should break down your forms using lists or nested values.
A form will create UserData instance with the bound values when given a Map:
But most of the time you’ll use forms from within an Action, with data provided from the
request. Form contains bindFromRequest , which will take a request as an implicit parameter. If you define
an implicit request, then bindFromRequest will find it.
Note: There is a catch to using get here. If the form cannot bind to the data, then get will throw an exception. We’ll
show a safer way of dealing with input in the next few sections.
You are not limited to using case classes in your form mapping. As long as the apply and unapply methods are
properly mapped, you can pass in anything you like, such as tuples using the Forms.tuple mapping or model
case classes. However, there are several advantages to defining a case class specifically for a form:
case class UserData(name: String, age: Int)
val userForm = Form(
mapping(
"name" -> text,
"age" -> number
)(UserData.apply)(UserData.unapply)
)
val anyData = Map("name" -> "bob", "age" -> "21")
val userData = userForm.bind(anyData).get
val userData = userForm.bindFromRequest.get
Form specific case classes are convenient. Case classes are designed to be simple containers of data, and provide out
of the box features that are a natural match with Form functionality.
Form specific case classes are powerful. Tuples are convenient to use, but do not allow for custom apply or unapply
methods, and can only reference contained data by arity (_1, _2, etc.)
Form specific case classes are targeted specifically to the Form. Reusing model case classes can be convenient, but
often models will contain additional domain logic and even persistence details that can lead to tight coupling. In addition, if
there is not a direct 1:1 mapping between the form and the model, then sensitive fields must be explicitly ignored to
prevent a parameter tampering attack.
48. Defining constraints on the form
The text constraint considers empty strings to be valid. This means that name could be empty here without
an error, which is not what we want. A way to ensure that name has the appropriate value is to use
the nonEmptyText constraint.
Using this form will result in a form with errors if the input to the form does not match the constraints:
The out of the box constraints are defined on the Forms object:
Defining ad-hoc constraints
You can define your own ad-hoc constraints on the case classes using the validation package.
You can also define ad-hoc constraints on the case classes themselves:
You also have the option of constructing your own custom validations. Please see the custom validations section
for more details.
Validating a form in an Action
Now that we have constraints, we can validate the form inside an action, and process the form with errors.
We do this using the fold method, which takes two functions: the first is called if the binding fails, and the
second is called if the binding succeeds.
val userFormConstraints2 = Form(
mapping(
"name" -> nonEmptyText,
"age" -> number(min = 0, max = 100)
)(UserData.apply)(UserData.unapply)
)
val boundForm = userFormConstraints2.bind(Map("bob" -> "", "age" -> "25"))
boundForm.hasErrors must beTrue
text : maps to scala.String , optionally takes minLength and maxLength .
nonEmptyText : maps to scala.String , optionally takes minLength and maxLength .
number : maps to scala.Int , optionally takes min , max , and strict .
longNumber : maps to scala.Long , optionally takes min , max , and strict .
bigDecimal : takes precision and scale .
date , sqlDate , jodaDate : maps to java.util.Date , java.sql.Date and org.joda.time.DateTime ,
optionally takes pattern and timeZone .
jodaLocalDate : maps to org.joda.time.LocalDate , optionally takes pattern .
email : maps to scala.String , using an email regular expression.
boolean : maps to scala.Boolean .
checked : maps to scala.Boolean .
optional : maps to scala.Option .
val userFormConstraints = Form(
mapping(
"name" -> text.verifying(nonEmpty),
"age" -> number.verifying(min(0), max(100))
)(UserData.apply)(UserData.unapply)
)
def validate(name: String, age: Int) = {
name match {
case "bob" if age >= 18 =>
Some(UserData(name, age))
case "admin" =>
Some(UserData(name, age))
case _ =>
None
}
}
val userFormConstraintsAdHoc = Form(
mapping(
"name" -> text,
"age" -> number
)(UserData.apply)(UserData.unapply) verifying("Failed form constraints!", fields => fields match {
case userData => validate(userData.name, userData.age).isDefined
})
)
49. In the failure case, we render the page with BadRequest, and pass in the form with errors as a parameter to the
page. If we use the view helpers (discussed below), then any errors that are bound to a field will be rendered in
the page next to the field.
In the success case, we’re sending a Redirect with a route to routes.Application.home here instead
of rendering a view template. This pattern is called Redirect after POST, and is an excellent way to prevent
duplicate form submissions.
Note: “Redirect after POST” is required when using flashing or other methods with flash scope, as new cookies will only
be available after the redirected HTTP request.
Showing forms in a view template
Once you have a form, then you need to make it available to the template engine. You do this by including the
form as a parameter to the view template. For user.scala.html , the header at the top of the page will look
like this:
Because user.scala.html needs a form passed in, you should pass the empty userForm initially when
rendering user.scala.html :
The first thing is to be able to create the form tag. It is a simple view helper that creates a form tag and sets
the action and method tag parameters according to the reverse route you pass in:
You can find several input helpers in the views.html.helper package. You feed them with a form field, and
they display the corresponding HTML input, setting the value, constraints and displaying errors when a form
binding fails.
Note: You can use @import helper._ in the template to avoid prefixing helpers with @helper.
There are several input helpers, but the most helpful are:
As with the form helper, you can specify an extra set of parameters that will be added to the generated Html:
userForm.bindFromRequest.fold(
formWithErrors => {
// binding failure, you retrieve the form containing errors:
BadRequest(views.html.user(formWithErrors))
},
userData => {
/* binding success, you get the actual value. */
val newUser = models.User(userData.name, userData.age)
val id = models.User.create(newUser)
Redirect(routes.Application.home(id))
}
)
@(userForm: Form[UserData])
def index = Action {
Ok(views.html.user(userForm))
}
@helper.form(action = routes.Application.userPost()) {
@helper.inputText(userForm("name"))
@helper.inputText(userForm("age"))
}
form : renders a form element.
inputText : renders a text input element.
inputPassword : renders a password input element.
inputDate : renders a date input element.
inputFile : renders a file input element.
inputRadioGroup : renders a radio input element.
select : renders a select element.
textarea : renders a textarea element.
checkbox : renders a checkbox element.
input : renders a generic input element (which requires explicit arguments).
@helper.inputText(userForm("name"), 'id -> "name", 'size -> 30)
50. The generic input helper mentioned above will let you code the desired HTML result:
Note: All extra parameters will be added to the generated Html, unless they start with the _ character. Arguments starting
with _ are reserved for field constructor arguments.
For complex form elements, you can also create your own custom view helpers (using scala classes in
the views package) and custom field constructors.
Displaying errors in a view template
The errors in a form take the form of Map[String,FormError] where FormError has:
The form errors are accessed on the bound form instance as follows:
Errors attached to a field will render automatically using the form helpers, so @helper.inputText with errors
can display as follows:
Global errors that are not bound to a key do not have a helper and must be defined explicitly in the page:
Mapping with tuples
You can use tuples instead of case classes in your fields:
Using a tuple can be more convenient than defining a case class, especially for low arity tuples:
Mapping with single
Tuples are only possible when there are multiple values. If there is only one field in the form,
use Forms.single to map to a single value without the overhead of a case class or tuple:
@helper.input(userForm("name")) { (id, name, value, args) =>
<input type="text" name="@name" id="@id" @toHtmlArgs(args)>
}
key : should be the same as the field.
message : a message or a message key.
args : a list of arguments to the message.
errors : returns all errors as Seq[FormError] .
globalErrors : returns errors without a key as Seq[FormError] .
error("name") : returns the first error bound to key as Option[FormError] .
errors("name") : returns all errors bound to key as Seq[FormError] .
<dl class="error" id="age_field">
<dt><label for="age">Age:</label></dt>
<dd><input type="text" name="age" id="age" value=""></dd>
<dd class="error">This field is required!</dd>
<dd class="error">Another error</dd>
<dd class="info">Required</dd>
<dd class="info">Another constraint</dd>
</dl>
@if(userForm.hasGlobalErrors) {
<ul>
@for(error <- userForm.globalErrors) {
<li>@error.message</li>
}
</ul>
}
val userFormTuple = Form(
tuple(
"name" -> text,
"age" -> number
) // tuples come with built-in apply/unapply
)
val anyData = Map("name" -> "bob", "age" -> "25")
val (name, age) = userFormTuple.bind(anyData).get
val singleForm = Form(
single(
"email" -> email
)
)
51. Fill values
Sometimes you’ll want to populate a form with existing values, typically for editing data:
When you use this with a view helper, the value of the element will be filled with the value:
Fill is especially helpful for helpers that need lists or maps of values, such as
the select and inputRadioGroup helpers. Use options to value these helpers with lists, maps and
pairs.
Nested values
A form mapping can define nested values by using Forms.mapping inside an existing mapping:
Note: When you are using nested data this way, the form values sent by the browser must be named
like address.street , address.city , etc.
Repeated values
A form mapping can define repeated values using Forms.list or Forms.seq :
When you are using repeated data like this, the form values sent by the browser must be
named emails[0] , emails[1] , emails[2] , etc.
Now you have to generate as many inputs for the emails field as the form contains, using
the repeat helper:
The min parameter allows you to display a minimum number of fields even if the corresponding form data are
empty.
Optional values
A form mapping can also define optional values using Forms.optional :
val email = singleForm.bind(Map("email", "[email protected]")).get
val filledForm = userForm.fill(UserData("Bob", 18))
@helper.inputText(filledForm("name")) @* will render value="Bob" *@
case class AddressData(street: String, city: String)
case class UserAddressData(name: String, address: AddressData)
val userFormNested: Form[UserAddressData] = Form(
mapping(
"name" -> text,
"address" -> mapping(
"street" -> text,
"city" -> text
)(AddressData.apply)(AddressData.unapply)
)(UserAddressData.apply)(UserAddressData.unapply)
)
@helper.inputText(userFormNested("name"))
@helper.inputText(userFormNested("address.street"))
@helper.inputText(userFormNested("address.city"))
case class UserListData(name: String, emails: List[String])
val userFormRepeated = Form(
mapping(
"name" -> text,
"emails" -> list(email)
)(UserListData.apply)(UserListData.unapply)
)
@helper.inputText(myForm("name"))
@helper.repeat(myForm("emails"), min = 1) { emailField =>
@helper.inputText(emailField)
}
case class UserOptionalData(name: String, email: Option[String])
val userFormOptional = Form(
mapping(
"name" -> text,
"email" -> optional(email)
52. This maps to an Option[A] in output, which is None if no form value is found.
Default values
You can populate a form with initial values using Form#fill :
Or you can define a default mapping on the number using Forms.default :
Ignored values
If you want a form to have a static value for a field, use Forms.ignored :
Putting it all together
Here’s an example of what a model and controller would look like for managing an entity.
Given the case class Contact :
Note that Contact contains a Seq with ContactInformation elements and a List of String . In
this case, we can combine the nested mapping with repeated mappings (defined
with Forms.seq and Forms.list , respectively).
And this code shows how an existing contact is displayed in the form using filled data:
)(UserOptionalData.apply)(UserOptionalData.unapply)
)
val filledForm = userForm.fill(User("Bob", 18))
Form(
mapping(
"name" -> default(text, "Bob")
"age" -> default(number, 18)
)(User.apply)(User.unapply)
)
val userFormStatic = Form(
mapping(
"id" -> ignored(23L),
"name" -> text,
"email" -> optional(email)
)(UserStaticData.apply)(UserStaticData.unapply)
)
case class Contact(firstname: String,
lastname: String,
company: Option[String],
informations: Seq[ContactInformation])
object Contact {
def save(contact: Contact): Int = 99
}
case class ContactInformation(label: String,
email: Option[String],
phones: List[String])
val contactForm: Form[Contact] = Form(
// Defines a mapping that will handle Contact values
mapping(
"firstname" -> nonEmptyText,
"lastname" -> nonEmptyText,
"company" -> optional(text),
// Defines a repeated mapping
"informations" -> seq(
mapping(
"label" -> nonEmptyText,
"email" -> optional(email),
"phones" -> list(
text verifying pattern("""[0-9.+]+""".r, error="A valid phone number is required")
)
)(ContactInformation.apply)(ContactInformation.unapply)
)
)(Contact.apply)(Contact.unapply)
)
53. Finally, this is what a form submission handler would look like:
Next: Protecting against Cross Site Request Forgery
def editContact = Action {
val existingContact = Contact(
"Fake", "Contact", Some("Fake company"), informations = List(
ContactInformation(
"Personal", Some("[email protected]"), List("01.23.45.67.89", "98.76.54.32.10")
),
ContactInformation(
"Professional", Some("[email protected]"), List("01.23.45.67.89")
),
ContactInformation(
"Previous", Some("[email protected]"), List()
)
)
)
Ok(views.html.contact.form(contactForm.fill(existingContact)))
}
def saveContact = Action { implicit request =>
contactForm.bindFromRequest.fold(
formWithErrors => {
BadRequest(views.html.contact.form(formWithErrors))
},
contact => {
val contactId = Contact.save(contact)
Redirect(routes.Application.showContact(contactId)).flashing("success" -> "Contact saved!")
}
)
}
54. Protecting against Cross Site Request Forgery
Cross Site Request Forgery (CSRF) is a security exploit where an attacker tricks a victims browser into making a
request using the victims session. Since the session token is sent with every request, if an attacker can coerce
the victims browser to make a request on their behalf, the attacker can make requests on the users behalf.
It is recommended that you familiarise yourself with CSRF, what the attack vectors are, and what the attack
vectors are not. We recommend starting with this information from OWASP.
Simply put, an attacker can coerce a victims browser to make the following types of requests:
An attacker can not:
Since GET requests are not meant to be mutative, there is no danger to an application that follows this best
practice. So the only requests that need CSRF protection are POST requests with the above mentioned content
types.
Play’s CSRF protection
Play supports multiple methods for verifying that a request is not a CSRF request. The primary mechanism is a
CSRF token. This token gets placed either in the query string or body of every form submitted, and also gets
placed in the users session. Play then verifies that both tokens are present and match.
To allow simple protection for non browser requests, such as requests made through AJAX, Play also supports
the following:
Applying a global CSRF filter
Play provides a global CSRF filter that can be applied to all requests. This is the simplest way to add CSRF
protection to an application. To enable the global filter, add the Play filters helpers dependency to your project
in build.sbt :
Now add the filter to your Global object:
Getting the current token
The current CSRF token can be accessed using the getToken method. It takes an implicit RequestHeader ,
so ensure that one is in scope.
All GET requests
POST requests with bodies of type application/x-www-form-urlencoded , multipart/form-
data and text/plain
Coerce the browser to use other request methods such as PUT and DELETE
Coerce the browser to post other content types, such as application/json
Coerce the browser to send new cookies, other than those that the server has already set
Coerce the browser to set arbitrary headers, other than the normal headers the browser adds to requests
If an X-Requested-With header is present, Play will consider the request safe. X-Requested-With is added to
requests by many popular Javascript libraries, such as jQuery.
If a Csrf-Token header with value nocheck is present, or with a valid CSRF token, Play will consider the request safe.
libraryDependencies += filters
import play.api._
import play.api.mvc._
import play.filters.csrf._
object Global extends WithFilters(CSRFFilter()) with GlobalSettings {
// ... onStart, onStop etc
}
56. Vivat! Hosanna! alléluia! ovohé! la foule nous entend; Dieu! quelle
queue! et vraiment, un public parfaitement couvert! La mise décente est
de rigueur. Il nous en vient de toutes les latitudes, de tous les coins de
l'univers, et de mille autres lieux.
Voici d'abord d'aimables militaires, d'agréables chasseurs d'Afrique (où
ces braves ne se fourrent-ils pas?)--deux Arabes de la tribu d'Ouleïd-
Chott-Mocktar;--un capitaine russe des bords du Volga;--un Indien du
Yisapour;--Cette tête ronde à la Titus représente l'Amérique,--et ce
terrible visage coiffé de son caftan, cet homme à l'œil noir, au nez
busqué, à la barbe féroce, n'est, ni plus ni moins qu'un cousin du kalifah
Ben-Sha-Djazzar-Ria-Engad-Sidi-Embarek, qui a été dernièrement envoyé
ad patres par le général Tempoure. Il est impossible d'avoir un public
plus varié et mieux choisi; le beau sexe y brille par son absence.
C'est le Temps, cet éternel Saturne, ce vieux dur à cuire, qui est le
metteur en scène, le directeur-général du spectacle que nous avons
l'honneur de vous offrir. Vous remarquerez qu'il ne ressemble à aucun
directeur connu, ni à M. Jouslin-Delasalle, ni à M. Crosnier, ni à M.
Delestre-Poirson; il est beaucoup plus joli, bien qu'il ne se soit pas rasé
ce matin.
Au moment on vous le voyez, le Temps fait disparaître de sa lanterne
magique le tableau des faits et gestes de l'année 1843, et par dessous
laisse voir un pan de l'histoire de l'année 1844 qui commence: c'est ce
dernier tableau (1844) que l'Illustration compte dérouler peu à peu, de
semaine en semaine, pour vos menus plaisirs, et avec l'aide du Temps,
vous donnant une grande représentation hebdomadaire de tout ce qui se
passera dans l'univers d'ici à 1845.--En attendant, et pour aller au plus
pressé, l'Illustration en personne, envieuse de vous faire sourire, va
représenter devant vous une pièce à tiroirs, un drame-vaudeville comico-
tragique, tiré du grand drame des petites misères du jour de l'an. Vous
avouerez qu'il est difficile de trouver nu sujet plus véritablement de
circonstance.
57. PREMIER ACTE
Une nuée de tambours se précipitent à travers la ville, au pas de charge,
exécutant sur la peau d'âne une symphonie à triple bacchanal, à
quadruple carillon, qui n'a vraiment de douceur que pour les sourds
complètement privés du plaisir de l'entendre; les citoyens pourvus des
trésors de l'ouïe ont te tympan parfaitement déchiré et se bouchent les
oreilles, pantomime qui n'a rien d'héroïque. C'est au bruit de ce concerto
assommant qu'on enterre le 31 décembre et que le 1er janvier vient au
monde, le but du tintamarre en question est d'avertir Paris et la banlieue
que le jour est venu de complimenter MM. les colonels, MM. les
généraux, MM. les maréchaux, et de leur donner roulement d'étrennes.
Le tambour-major se livre alors à toutes les
grâces d'une délirante pantomime, à toutes
les beautés d'attitudes triomphantes qui
caractérisent ce magnifique guerrier, doué
d'une si belle canne.
La canne du tambour-major est un meuble
agréable, j'en conviens; mais si elle a ses
douceurs, elle a bien ses désagréments:
demandez, plutôt à ce particulier qui s'est
mis en course ce matin pour aller souhaiter la bonne année à sa tante;
demandez-lui ce qu'il en pense. Demandez-le à cet estimable industriel
qui vient d'ouvrir sa boutique pour affriander le jour de l'an. Il est clair
58. que si l'amabilité du tambour-major et ses superbes moustaches donnent
dans l'œil, sa canne y donne aussi.
Éveillé par le ra et le fla des tambours de la
légion, le lieutenant a revêtu les insignes de
son grade; il se dispose à rejoindre ses chers
camarades, et à faire sa visite au château
pour y déposer sa fidélité, en forme de carte
de visite; le guerrier est parfaitement
chaussé, culotté, coiffé et ficelé; il a le nez
rouge, ce qui est d'uniforme; cependant on
s'aperçoit, à son col de chemise s'élançant
vers l'oreille, qu'il aurait autant aimé finir son somme que de déposer son
hommage.
Au jour de l'an, tout n'est pas rose dans le militaire... et dans le civil
donc! Ici la toile se baisse... et se relève sur le second acte.
DEUXIÈME ACTE.
Le théâtre représente la chambre à coucher d'un gentleman parisien; le
coup d'œil en est magnifique. Les décors sont de MM. Sechan, Dieterle,
Cambon et Cicéri.--Le gentilhomme, est étendu dans son lit, sauf votre
respect, et coiffé du casque à mèche classique que le foulard a détrôné,
le révolutionnaire! Mais notre héros tient aux saines doctrines: il a fait
récemment le voyage de Belgrave-Square. Hier, il s'était endormi, c'était
le soir de la Saint-Sylvestre, le teint frais et les joues rondes, humant les
rêves les plus parfumés. L'infortuné se réveille le 1er janvier dans l'état
ou vous le voyez: il n'est certes pas beau; le jour de l'an en est cause, le
jour de l'an qui vient d'enfoncer sa porte sous la forme de sa couturière,
de sa femme de ménage, de son tambour, du bedeau de sa paroisse, du
clerc de son huissier, du porteur de son journal, du garçon de son tailleur
et de tous les moustiques dévorants que le 1er janvier fait naître.
Il en fera une maladie, c'est sûr! mais sa bourse est encore plus malade
que lui. Dans l'intention de ménager la santé, de cette pauvre bourse,
qui n'a pas les reins forts, il regarde par sa fenêtre, guettant l'heure où le
portier, homme illustre, est occupé à balayer sa cour; paré, dressé, ciré,
59. cravaté, orné de pied en cap et prêt à courir
la visite; l'ingénieux Parisien saisit
adroitement l'occasion et s'esquive au
moment où la loge est vide. Quel fin
diplomate! Il s'épargne, par ce tour adroit, la
douleur de tirer de sa poche 3 francs 50
centimes d'étrennes au portier. C'est autant,
de gagné, pour la caisse d'épargne.
Mais il lui en
cuira! Si la
vengeance était
exilée de la terre, elle se réfugierait dans le
cœur du concierge qui n'a pas reçu
d'étrennes; vous en avez sous les yeux une
preuve mémorable. En rentrant le soir,
l'homme à la caisse d'épargne a beau frapper
et sonner à tour de bras, le portier n'ouvre
pas; il a ses 3 franc 50 centimes sur le cœur,
un plutôt il ne les a pas! et le malheureux
locataire est obligé de passer la nuit sur la
borne, oreiller rembourré de pierres de taille.
Du fond de son antre, l'affreux concierge
murmure ces mots atroces: «Enfoncé, vilain
ladre!»
Il avait cependant grand besoin de consommer sa nuit dans son lit bien
chaud, car il vient de passer une journée remplie de tribulations; pour
lui, le jour de l'an n'a été que pluies et bosses, comme l'acte situant vous
l'apprendra.
TROISIÈME ACTE.
A peine était-il sorti, à la suite de ce malin tour que vous savez; à peine
avait-il le pied dans la rue, qu'il fut accosté par le fils puîné d'un de ses
amis intimes. Ce détestable moutard, vulgairement appelé To-tor, se
précipita à sa rencontre: «Bonjour, papa Chose, s'écria-t-il avec cette
grâce qui caractérise l'enfance; ohé! z'veux mes étrennes, z'veux un
60. polichinelle!» En vain cherche-t-il à se soustraire à cet impôt indirect; le
terrible To-tor n'en démord pas, et, le saisissant par la basque de habit
(son habit neuf!!), il le tire affreusement du coté de la boutique de
joujoux. Lui de s'enfuir; To-tor de tirer de plus belle, d'une part l'habit, de
l'autre le seigneur Polichinelle; si bien que l'habit reste et que To-tor
s'évanouit. La bonne, une ancienne d'Abd-el-Kader, contemple ce
spectacle déchirant avec l'immobilité qui caractérise la nation hottentote.
Dans sa chute, le déplorable To-tor s'est
enfoncé une côte, et s'est considérablement
endommagé l'occiput; tout porte à croire que
la famille des Gougibus est menacée de
s'éteindre, avant la fin de la semaine, avec ce
dernier de ses descendants.
Et, en effet, M. et madame Gougibus ne sont
plus capables de se transmettre davantage:
ils sont hors d'âge, comme le témoigne, le
portrait que nous vous donnons de ces deux
illustres conjoints; portrait authentique, pris au moment où cette
excellente mère et ce père excellent revenaient au logis chargés de
pantins et de polichinelles pour leur To-tor. Notre héros, qui les a
reconnus, les suit de loin d'un œil hagard, d'un œil de sergent de ville; il
sent que le cas est grave.
Au lieu donc d'entrer chez les Gougibus, il fait
un détour, et se dit: «Eh bien! allons
souhaiter la bonne année à ce cher Babylas.»
Il entre en effet chez Babylas, qui n'est pas
très-bien portant, et le reçoit assis sur une
chaise que je ne qualifierai pas. Babylas est
marié et père de nombreux enfants: il ne sait
pas trop comment cela lui est venu; mais
n'importe! il s'en rapporte à madame
Babylas. Ces enfants sont nés excessivement
caressants: c'est là leur moindre défaut. A peine ont-ils aperçu l'ami de
leur père, qu'ils se précipitent dans ses bras pour lui souhaiter la bonne
année: c'est une véritable scène d'abordage et de mât de cocagne;
61. jamais le jour de l'an ne manifesta une tendresse plus étouffante; l'un
grimpe sur le dos du malheureux, l'autre le prend par le cou; celui-ci se
suspend à ses reins, celui-là à sa barbe; et quels baisers! Le célèbre
Hercule du Nord n'avait pas plus d'agrément quand il déjeunait avec un
fer rouge et quatre poids de cinquante livres sur l'estomac.--Le père
Babylas jouit avec attendrissement de ce spectacle domestique: ça le
soulage.
Après une
rencontre si
brûlante, ou
éprouve
naturellement le
besoin de prendre
moindre chose
pour se rafraîchir,
un verre d'eau
sucrée, un
échaudé, un petit
verre de rhum. Ainsi fait notre homme. C'est
lui-même en personne qui vient de s'asseoir dans ce café, sur ce fauteuil,
autour de cette table ronde. «Au moins là, pense-t-il, le jour de l'an ne
viendra pas me prendre ma bourse ou m'étrangler!» L'homme propose,
mais le garçon dispose. Au moment ou la victime de cette Iliade digne de
mémoire a pris son chapeau et sa canne pour se retirer tranquillement,
le garçon arrive armé du cornet d'amandes grillées qu'il présente, sous
prétexte de bonne année, au bourgeois effaré; il a pris, pour réussir, son
air le plus penché, son geste le plus élégant, son plus anacréontique
sourire. Mais qui a su échapper à un portier ne donnera pas dans le
cornet d'un garçon. «Merci, dit l'autre, je ne peux pas souffrir les
pralines; ça m'incommode.» Et il part sans délier sa bourse, emportant
après ses talons cette apostrophe du garçon: «Vieille bête, va!»--Ici il y a
un entr'acte: l'orchestre et le souffleur déclarent qu'il leur serait agréable
de se reposer; vous pouvez en faire autant ô mes très vénérés
spectateurs, et aller vous promener.... Pan! pan! pan! à vos places.
QUATRIÈME ACTE.
62. Contemplez ce mortel coiffé d'une énorme
boîte de satin, étendant les bras, écartant les
jambes, et cherchant sa route à talons,
comme un simple quatre-vingt: c'est la
continuation de notre martyrologe.--Il
traversait la rue des Enfant-Rouges, songeant
encore avec effroi au cornet de pralines, et
cependant reprenant peu à peu ses esprits et
commençant à mettre la main dans ses
poches, comme un bon bourgeois qui rêve à
ses quartiers de rentes, et se promet de vivre
dans sa maison, le dos au feu, le ventre à
table. Tout à coup,--ô fortune infidèle!--une
fenêtre s'ouvre, et du haut d'un cinquième
étage au-dessus de l'entresol, une énorme
boîte s'échappe et va le coiffer comme vous
le voyez, là: bonnet imperméable, très-peu commode!
C'est tout simplement une fille qui s'étant mise au balcon avec une boîte
à ménage que son parrain venait de lui apporter, a laissé choir l'objet, qui
n'a rien de plus pressé que de tomber en plein sur le crâne de notre
illustre ami, et de s'y plonger jusqu'aux oreilles. O jour de l'an, voilà de
tes chapeaux!
Il fit cette réflexion profonde, que
c'était là une dragée difficile à
digérer; après quoi, s'étant recoiffé
et remis de son mieux sur ses
jambes, il reprit sa route et gagna la
rue Saint-Honoré sans trop
d'accident. Un proche parent du
grand-duc Hiltchinkenkoff passait
précisément par là au galop, traîné
dans une voiture attelée de deux
quadrupèdes et de quatre valets; monseigneur s'en allait présenter ses
souhaits de bonne année à n'importe quel potentat de l'Europe alors du
passage à Paris. «Diable! rumina notre ami en voyant ce magnifique
équipage, voilà un noble étranger qui n'est pas trop mal mené; excusez!
63. que ça d'omnibus! et il s'apprêtait à ôter respectueusement son chapeau,
comme fait tout piéton qui sent où le bât le blesse. Le proche parent du
grand-duc, ému de cette politesse,
sans seulement mettre le nez à la
portière, envoya, par le ministère de
ses roues et de ses deux alezans,
une énorme gratification de boue et
de crotte au visage de l'estimable
particulier; son pantalon en fut zébré
et son visage moucheté. Remarquez
bien que si le jour de l'an n'avait pas lui, notre homme ne serait pas venu
dans la rue Saint-Honoré, il n'aurait pas rencontre le proche parent du
grand-duc allant porter au potentat susnommé son bonjour et son bon
an, et nous n'aurions pas sous les yeux le tableau humiliant d'un citoyen
français crotté comme ne le fut jamais Colletet, qui cependant, au dire de
Boileau, le fut jusqu'à l'échine!
Le décrotteur a été inventé pour cette
situation; sans l'homme crotté, certainement
le décrotteur n'existerait pas; il est donc
logique que le crotté, dans sa détresse, se
réfugie chez le décrotteur, lui demande aide
et protection avec un coup de brosse. La
victime du proche parent du grand-duc n'en
fait pas d'autre; il entre dans la boutique du
l'artiste et se hisse sur la banquette dans
l'attitude peu gracieuse d'un mortel qui n'a
pas à se louer du destin.
L'artiste fait son office en conscience frotte,
brosse, émonde, prodigue le cirage, et remet
le malheureux dans un état moins affligeant. Le crotté est décrotté. Il
entrevoit un horizon plus serein. Mais où le jour de l'an ne va-t-il pas se
nicher? il s'était, là-haut, glissé dans un cornet de pralines; il se présente
ici sous la forme d'une tirelire: l'artiste décrotteur l'a déposée, cette
tirelire maudite, aux pieds de son client, comme pour placer la
récompense à côté du bienfait; et comme tout décrotteur a de la
littérature pour avoir ciré les bottes de M. Ligier, de M. Bocage ou de M.
64. Victor Hugo, le nôtre, à l'appui de sa pétition pour étrennes, entonne et
détonne une harangue en vers, et de vrais alexandrins!--Le décrotté,
hors de lui, se soulève sur ses deux poings, et attend le moment du
prendre la fuite, en brûlant la politesse à la tirelire; le grossier!
Le malheur instruit les hommes. «Puisqu'on est éclaboussé quand ou va
à pied comme un ignoble barbet, dit-il, en prenant un cabriolet,
j'éclabousserai les autres!» Sublime réflexion! assaisonnée d'une légère
dose de fiel; car le cœur humain n'est pas bon quand il s'y met. Il
s'élance donc, d'un air de prince héréditaire, dans un cabriolet régie.
Arrive le tambour-major et ce qui s'ensuit, donnant l'aubade au colonel;
le cheval se dresse, le cabriolet roule, et notre homme va mesurer le
pavé; là, il prononce ces mots d'une moralité profonde: «A pied, du
moins, on ne risque pas de tomber de voiture!» Tandis que le chirurgien
du coin est occupé de le panser, reprenons haleine.
CINQUIÈME ACTE.
Le cocher, à la rigueur, aurait bien pu relever
le pauvre diable après sa chute; dans un
autre temps, il se serait fait un vrai plaisir de
commettre cette bonne action et de
prodiguer les consolations à l'affligé: le
cocher est naturellement sensible dans tout
le courant de l'année; mais, au jour de l'an, il
est plus dur que le cuir de ses chevaux. Vous
vous étalez de vos quatre membres, dans ce
bienheureux jour, le cocher vous laisse faire,
et, s'inclinant, la casquette à la main, vous
souhaite une bonne année. Quel affreux calembour! Enfin, le voilà
encore debout: il s'en trouve quitte pour la peur. Redevenu piéton, le
pauvre hère chemine, un mitron se trouve à sa rencontre; le mitron porte
un souper fin à un lion et à une biche de l'Opéra qui se préparent à
célébrer le premier de l'an à la façon de
Lucullus, il est nuit, nuit profonde comme
dans les mélodrames du M. Anicet Bourgeois;
le mitron heurte l'homme, l'homme heurte le
mitron, se renvoyant l'un l'autre comme une
65. balle bondissant sur une raquette, et le souper tombe à plat ventre; un
chien qui passait par là, et cherchait un dîner en ville, profite de
l'occasion pour se mettre à table sans serviette.
ÉPILOGUE
Il est quatre heures du matin... Notre héros
malencontreux s'est décidé à se lever de la
borne qui lui sert de lit de plume depuis
minuit, et à frapper un dernier coup de
marteau: ce coup est si désespéré et si
lamentable, qu'enfin le portier n'y résiste
plus, et tire le cordon; le malheureux entre
tout joyeux; mais, ô ruse de portier
diabolique! ô trame infernale! les 3 francs 50
cent. ne sont pas suffisamment expiés par
toutes ces couleuvres que le récalcitrant
locataire avale depuis ce matin: il faut que ce
concierge sans âme, sous-prétexte de zèle,
lui plonge, à bout portant, un bougeoir
allumé dans la poitrine; le jabot prend feu; appelez, les pompiers!
Ou éteint l'incendie, et l'incendie monte
l'escalier quatre à quatre. Dieu soit loué! le
voici à sa porte; il tire sa clef, l'insinue dans
la serrure. O Jupiter! il va enfin se dorloter
sur sa couche!--Mais pourquoi cette mine
atroce et désespérée? Pourquoi ce furieux
chapeau jeté sur l'oreille: La serrure a refusé
passage, et vainement la clef a tenté de se
faire jour à travers un épais bataillon de
cartes de visites que des mains forcenées ont
entassées dans le trou. Jour de l'an! jour de
l'an! finiras-tu?
Sa seule ressource est d'entrer chez lui par
bris de serrure et par une sorte d'attaque
nocturne. Il y est enfin, et déjà il a ôté son habit et mis ses pantoufles;
66. mais, ô rage! un élève de Courvoisier a
profité de l'occasion du jour de l'an pour lui
faire sa visite par la fenêtre, et dévaliser mon
homme. Après avoir examiné sa commode et
sa cheminée, il dresse inventaire d'une
montre, d'un tire-botte, d'un paletot, d'un
bâton de cire à cacheter, d'une pendule, d'un
morceau de savon à barbe, d'une édition des
œuvres de M. Casimir Bonjour, et de cinq
paires de chaussettes dont le bandit a fait sa
proie. Il se couche néanmoins après s'être
arraché une poignée de cheveux; et sa nuit
est pleine de portes, de portiers, de décrotteurs, de princes allemands,
de petits garçons, de tambours et de polichinelles..... et murmure ces
mots dans un affreux cauchemar: «Jour de l'an!... étrennes!... visites!...
ah! ah! oh! eh! ouf!»
Ici la toile se baisse pour ne plus se relever. Excusez les fautes de
l'auteur.
67. Éphémérides.
Parmi les personnages célèbres à des titres divers, et dont
l'histoire
doit garder les noms, le 1er janvier a vu mourir;
En 379, Saint Basile, évêque de Césarée;
En 1380, Charles le Mauvais, roi de Navarre;
En 1515, Louis XII, roi de France;
En 1560, le poète français Joachim du Bellay;
En 1715, le poète anglais Wycherley;
En 1763, l'abbé Dangeau, grammairien si passionné qu'il rompit avec
toutes ses maîtresses qui ne mettaient pas l'orthographe; et qu'un
jour,
entendant parler d'une révolution prochaine, il s'écria. «Arrive ce
qui
pourra, j'ai dans mon portefeuille 2,000 verbes français bien
conjugués;»
En 1800, le naturaliste Daubenton;
En 1817, le chimiste Klaproth.
Le 1er janvier s'est toujours montré favorable à la liberté.--Le 1er janvier
1308, éclata la révolution qui assura l'indépendance de la Suisse.--Le 1er
janvier 1804, Saint-Domingue se déclara indépendante et reprit son nom
de Haïti.--Le 1er janvier 1815, le Chili proclama son indépendance.--Le
1er janvier 1820, l'infortuné Riégo proclama, à Cadix, la constitution des
Cortès, et deux ans plus tard la Colombie promulgua sa constitution.
Parmi les autres événements historiques, scientifiques ou littéraire, qui
eurent lieu le 1er janvier, nous mentionnerons la prise d'Harfleur sur les
Anglais (1450); le voyage de Charles-Quint en France (1510); la levée du
siège de Metz (1554); la création du ministère de police (1796); l'entrée
en fonctions du Corps-Législatif et du tribunat (1800); la reddition de
Dantzick (1814); la première représentation Phèdre (1677); la
découverte de Céres par Piazzi (1801), etc., etc.
Que se passera-t-il le 1er janvier 1844? Nous n'osons pas le prédire;
mais... qui vivra verra.
69. Modes de 1844, par Grandville.--
Rébus.
Comment s'habillera l'année 1844? C'est là une grave question, une
question qu'il serait bon de soumettre à un conclave de couturières et de
marchandes de modes; ces demoiselles (j'aime à le croire) sont
compétentes en cette matière, et peuvent seules annoncer l'avenir
réservé au cotillon; car elles sont naturellement les Lenormand et les
Cassandre de la mode. Pourquoi, en effet, ne la prédiraient-elles pas,
puisqu'elles l'inventent? Nous dirons la même chose de MM. les tailleurs,
qui ont inventé, entre autres découvertes commodes, les habits qui se
déchirent comme de l'amadou, et les pantalons qu'on ne peut pas
mettre: mode excessivement agréable pour les personnes qui ont besoin
d'allumer un cigare, et pour celles qui tiennent à ne pas être trop vêtues.
Quoi qu'il en soit, nous devons à l'indiscrétion d'un tailleur de la place de
la bourse, et d'une marchande de modes de la rue Vivienne, le bonheur
de pouvoir vous offrir ce fac similé du costume masculin et féminin qui
aura cours en 1844, et sera ce qu'on appelle bien porté.
Costume de femme: bonnet à la vieille; paletot: manchettes de
fourrures; robe à volant, en lambrequin; cigare il trois sous.
Costume d'homme: paletot-sac, canne et parapluie; lunettes; ou
continuera à porter beaucoup de barbe, mais très-peu de cheveux.
Costume d'enfant: Scotto-Jean-Jacques.
Ces modes ne sont pas neuves; mais on ne peut pas dire non plus
qu'elles soient consolantes; mais que voulez-vous? le monde se fait
vieux, et l'humanité n'est pas gaie: il est logique qu'elle prenne un habit
uniforme.
Maintenant, chers lecteurs, en attendant que vous passiez chez, votre
tailleur ou chez votre couturière pour vous faire habiller à la 1844,
70. permettez-moi de vous
offrir vos étrennes, au
nom de ma très-chère
mère l'Illustration: j'ai
cherché ce qui pourrait
vous convenir le mieux,
car j'ai le désir sincère de
vous plaire. Ma première
idée était de vous
envoyer à chacun, dans
une papillote, un contrat
de 50,000 livres de
rentes, 5 pour 100; mais
il m'a semblé plus délicat
de vous offrir le présent
rébus. Le rébus fait votre
bonheur, je le sais:
veuillez donc accepter
celui-ci avec mes salutations bien cordiales.
72. *** END OF THE PROJECT GUTENBERG EBOOK L'ILLUSTRATION,
NO. 0044, 30 DÉCEMBRE 1843 ***
Updated editions will replace the previous one—the old editions will
be renamed.
Creating the works from print editions not protected by U.S.
copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.
START: FULL LICENSE
74. PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the free
distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only be
used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
75. 1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright law
in the United States and you are located in the United States, we do
not claim a right to prevent you from copying, distributing,
performing, displaying or creating derivative works based on the
work as long as all references to Project Gutenberg are removed. Of
course, we hope that you will support the Project Gutenberg™
mission of promoting free access to electronic works by freely
sharing Project Gutenberg™ works in compliance with the terms of
this agreement for keeping the Project Gutenberg™ name associated
with the work. You can easily comply with the terms of this
agreement by keeping this work in the same format with its attached
full Project Gutenberg™ License when you share it without charge
with others.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside the
United States, check the laws of your country in addition to the
terms of this agreement before downloading, copying, displaying,
performing, distributing or creating derivative works based on this
work or any other Project Gutenberg™ work. The Foundation makes
no representations concerning the copyright status of any work in
any country other than the United States.
1.E. Unless you have removed all references to Project Gutenberg:
1.E.1. The following sentence, with active links to, or other
immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project Gutenberg™
work (any work on which the phrase “Project Gutenberg” appears,
or with which the phrase “Project Gutenberg” is associated) is
accessed, displayed, performed, viewed, copied or distributed:
76. This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this eBook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is derived
from texts not protected by U.S. copyright law (does not contain a
notice indicating that it is posted with permission of the copyright
holder), the work can be copied and distributed to anyone in the
United States without paying any fees or charges. If you are
redistributing or providing access to a work with the phrase “Project
Gutenberg” associated with or appearing on the work, you must
comply either with the requirements of paragraphs 1.E.1 through
1.E.7 or obtain permission for the use of the work and the Project
Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is posted
with the permission of the copyright holder, your use and distribution
must comply with both paragraphs 1.E.1 through 1.E.7 and any
additional terms imposed by the copyright holder. Additional terms
will be linked to the Project Gutenberg™ License for all works posted
with the permission of the copyright holder found at the beginning
of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files containing a
part of this work or any other work associated with Project
Gutenberg™.
1.E.5. Do not copy, display, perform, distribute or redistribute this
electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
77. Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com