Chapter 5. Dealing with Content

A web application always has, at some point, the need to deal with multiple types of content. Common content types include JSON, XML, HTML, but there could also be images or even videos to be stored and streamed. Play! 2 provides a clean way of dealing with such content types with the help of body parsers.

We won't cover the implementation details of such body parsers, because it's purely based on a functional concept, Iteratee, and thus their implementations are in Scala only. However, we'll see how they are used and how we can gain benefits from them.

In this chapter, we'll update and clean up a bit of what we have been doing so far in order to enable several workflows. So we will only be using examples we have learned up to now. The following is what will be achieved:

  • Make the Chat and Item classes persistent using Ebean
  • Create a link between an item and a user (a user's reply in a chat)
  • Introduce a new type, Image, that will be part of a chat as an attachment
  • Enable a user to connect
  • Browse all chat instances
  • Allow the connected user to reply in a chat
  • Allow the connected user to attach an image to a chat
  • Show examples of UIs
  • Create an action that outputs a requested image
  • Create an action that provides an Atom feed of all chats which have specific users getting involved (kind of like following)

Note

In order to keep the chapter short and to the point, we'll only see the Java part. Keep in mind that the Scala version is little different for this level of detail.

Body parsing for better reactivity

As noted earlier, the way to manage content in Play! 2 is to use instances of body parsers. In brief, a body parser is a component that is responsible for parsing the body of an HTTP request as a stream to be converted into a predefined structure. This has a common sense ring to it, however their strength is in their way of consuming the stream—in a reactive fashion.

Reactivity, in this context, is meant to describe a process where an application won't block on a task that is actually idle. As a stream consumption task is idle when no bytes are incoming, a body parser should behave the same. It will read and construct an internal representation of the incoming bytes. But it can also decide at any time that it has read enough to terminate and return the representation. On the other hand, if no more bytes are coming into the stream, it can relax its thread in favor of another request; it pauses its work until new bytes are received.

Thinking about an HTTP request that is sending a bunch of XML content, the underlying action can use the XML-related body parser to handle it correctly (read reactively); that is, by parsing it and providing a DOM representation.

To understand what a body parser actually is, we'll first look at how they are used—in the actions. An action in Play! 2 represents the piece of software that is able to handle an HTTP request; therefore, they are the right place to use a body parser.

In the Java API, an action is allowed to be annotated with the Of annotation available in the BodyParser class. This annotation declares the expected type of request routed to it, and it requires a parameter that is the class of the parser that will be instantiated to parse the incoming request's body.

The following screenshot shows an example:

Body parsing for better reactivity

Isn't this helpful? We've gone from a request to a W3C document, in a single line. Functionally speaking, this works because an action is semantically a higher-order function that takes a body parser and generates a function that takes a request (and so its body) and results in an HTTP response (result). This result will then be used to construct the HTTP response by Play! 2.

In Java, it is not all that obvious how to create a higher-order function. A good way, however, to achieve this was to add an annotation. An annotation can be processed at runtime in order to execute the right body parser (in this case).

To illustrate this, we'll have a quick look at the Scala version:

Body parsing for better reactivity

With this Scala version, it is easy to see that an action is dealing with a function from a request to a response.

There are a plenty of predefined body parsers that can be used to handle our requests, and they are all defined in the BodyParser class as static inner classes. One can have a specific behavior to be applied on its expected request body, and even though a body parser has to be implemented in Scala, a Java coder can simply extend these current implementations. Actually, they're already providing enough control to cover all custom use cases.

So, we have in our hands tools to handle the following content types:

  • JSON
  • XML
  • URL form encoded
  • Multipart (for uploading files)
  • Text
  • Raw (fallback)

As we can see from the previous list, there is, obviously, an implementation for the x-www-form-urlencoded content type. Indeed, this is the parser we've used so far to retrieve data from the client side. For example, using POST requests throughout HTML forms.

But wait, we never had to add such annotations to our actions, and, moreover, we've never looked in the parsed result. That's true, Play! 2, as a great framework, is already doing a lot of stuff for us. And that's because it's a web framework; it takes advantage of HTTP; in this case, using the content-type header.

Based on this hint, it seems obvious that Play! Framework 2 will look in this header to find the right parser to apply. So annotations are mandatory, but where did we use them previously? In the bindFromRequest method, of course. Let's see how.

In the previous chapter we have used form instances, and we fed them some data through the client. Those instances were applied on the request using the bindFromRequest method, and this method's job was to look for data according to the provided content type. And, of course, this content type was set in the header by the HTML forms themselves.

Indeed, an HTTP GET will send data in the request URL (query string), where an HTTP POST will be sent with a body that contains all data encoded by default as URL parameters (that is, x-www-url-encoded).

So, we can now give an overview of what the bindFromRequest method does. When we ask a form to be filled in with data, this method will:

  • Gather data as URL-form encoded data, if any
  • Gather data from parts (if the content type is multipart-data)
  • Gather data as JSON-encoded, if any
  • Gather data from the query string (that's why GET requests were working as well)
  • Fill in the form's data with all of them (and validate)

You might be wondering the worth of such annotations; the quick answer to that is they allow new types of parsers, but they can also enforce certain actions' requests to match a given content type.

Another advantage of such annotations is that they allow us to extend or narrow the length of the body that can be handled. By default, 100 K are accepted, and this can be either configured (parsers.text.maxLength=42K) or passed as an argument to the annotation.

With all of this in mind, we are now ready to implement these concepts in our code, and what we're going to do is to update our code base to create a kind of forum. A forum where one can log in, initiate a chat, reply to non-closed ones (based on their date), or even attach files to them.

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

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