Filters

In most applications, we need to perform the same operation for all requests. We might be required to add a few fields to all the responses at a later stage, after we have already defined all the actions needed for our application.

So, in this case, will we have to update all the Actions?

No. This is where the filter API comes to our rescue. We don't need to modify how we define our Actions to solve the problem. All we need to do is define a filter and use it.

Let's see how we can define our filter:

import org.joda.time.DateTime 
import org.joda.time.format.DateTimeFormat
import play.api.mvc._
import play.api.http.HeaderNames._ 
import play.api.libs.concurrent.Execution.Implicits.defaultContext 

object HeadersFilter {
  val noCache = Filter { 
    (nextFilter, rh) => 
      nextFilter(rh) map { 
        case result: Result => addNoCacheHeaders(result) 
      } 
  } 

  private def addNoCacheHeaders(result: Result): Result = { 
    result.withHeaders(PRAGMA -> "no-cache", 
      CACHE_CONTROL -> "no-cache, no-store, must-revalidate, max-age=0", 
      EXPIRES -> serverTime) 
  } 

  private def serverTime = { 
    val now = new DateTime() 
    val dateFormat = DateTimeFormat.forPattern( 
      "EEE, dd MMM yyyy HH:mm:ss z") 
    dateFormat.print(now) 
  } 
} 

The HeadersFilter.noCache filter adds all the headers to a response, which are required to disable caching in browsers. PRAGMA, CACHE_CONTROL, and EXPIRES are constants provided by play.api.http.HeaderNames.

Now, to use this filter, we would need to update the global settings for the application.

The global settings for any Play-based application can be configured using a global object. This is an object that's defined with the name Global and is placed in the app directory. We will find out more about global settings in Chapter 7, Playing with Globals.

There are two ways of defining how the filter should be used. These are:

  1. Extending the WithFilters class instead of GlobalSettings for the global object.
  2. Invoking the filter manually in the global object.

    An example of using WithFilters is:

    object Global extends WithFilters(HeadersFilter.noCache) { 
      // ... 
    }

    Now, let's see how this can be done manually:

    object Global extends GlobalSettings {
      override def doFilter(action: EssentialAction): EssentialAction = HeadersFilter.noCache(action) 
    }

    In Play, a filter is defined similar to Action—there is a filter trait, which extends EssentialFilter and a helper filter object. The helper filter is defined as:

    object Filter {
      def apply(filter: (RequestHeader => Future[Result], RequestHeader) => Future[Result]): Filter = new Filter { 
        def apply(f: RequestHeader => Future[Result])(rh: RequestHeader): Future[Result] = filter(f, rh) 
      } 
    }

    In this code snippet, the apply method calls a new filter, which is the filter trait.

    Multiple filters can be applied for a single application. If WithFilters is used, they are applied in the specified order. If they are set manually, we can use the filters object used internally by the apply method of the WithFilters class. The Filters object is defined as follows:

    object Filters {
      def apply(h: EssentialAction, filters: EssentialFilter*) = h match { 
        case a: EssentialAction => FilterChain(a, filters.toList) 
        case h => h 
      } 
    }

    FilterChain is another helper object used to compose EssentialAction from a combination of EssentialAction and multiple EssentialFilters:

    object FilterChain {
      def apply[A](action: EssentialAction, filters: List[EssentialFilter]): EssentialAction = new EssentialAction { 
        def apply(rh: RequestHeader): Iteratee[Array[Byte], Result] = { 
          val chain = filters.reverse.foldLeft(action) { (a, i) => i(a) } 
          chain(rh) 
        } 
      } 
    }
  3. Filters are recommended when some operation is to be performed indiscriminately for all routes. Play provides a filter module, which has a GzipFilter, SecurityHeadersFilter, and CSRFFilter.
..................Content has been hidden....................

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