Unfiltered 

Unfiltered is a toolkit for servicing HTTP requests in Scala. It provides a consistent vocabulary for handing requests on various server backends, without impeding direct access to their native interfaces.

Version 0.8.4 Release Notes

This documentation walks through basic functionality of the library. You may also want to refer to Unfiltered’s scaladocs

Try Unfiltered 

It’s not hard to write a request handler in the Scala console using Unfiltered. The tricky part is getting everything on the classpath.

Play Project 

The approach recommended here uses giter8, a tool for setting up projects based on templates stored in github. Assuming you don’t have giter8 installed and you are on a network-connected Linux or Mac, it’s easy to fix that.

curl https://raw.githubusercontent.com/n8han/conscript/master/setup.sh | sh

That is conscript. Its setup.sh places a permanent (assuming you don’t delete it) executable script in ~/bin/cs. At some point you may want to add ~/bin to your executable search path, but these instructions will not assume it is.

~/bin/cs n8han/giter8

That installs a g8. Now you have a script to run giter8. The next step creates a sbt project under the current working directory.

~/bin/g8 unfiltered/unfiltered --name=justplayin

Okay, finally we can use this project with sbt to get a console for Unfiltered. You do have sbt setup, don’t you?

cd justplayin
sbt console

Consoled 

Now that you have a scala> prompt with the unfiltered-filter and unfiltered-jetty modules on the classpath, let’s have some fun.

import unfiltered.request._
import unfiltered.response._
val echo = unfiltered.filter.Planify {
  case Path(Seg(p :: Nil)) => ResponseString(p)
}

This filter echo would work with any servlet container. We can use it in a Jetty server right now.

unfiltered.jetty.Server.anylocal.plan(echo).run()

The startup message tells you which open port was selected, and by default it is only listening to requests from 127.0.0.1. So on the same machine, you can make requests to your server. e.g.

curl http://127.0.0.1:<the right port>/hello+world

Fancy desktop web browsers will work too. Notice that exactly one path segment is required for the filter to respond to the request. If you ask for the root path or a deeper path, the echo filter will not handle the request and Jetty responds with a 404 page.

If we want to handle any request, we could broaden the pattern matching expression. (Press enter to stop the running server.)

val echoNice = unfiltered.filter.Planify {
  case Path(Seg(p :: Nil)) => ResponseString(p)
  case _ => ResponseString(
    "I can echo exactly one path element."
  )
}
unfiltered.jetty.Server.anylocal.plan(echoNice).run()

Or we could define another filter chain it to the first.

val nice = unfiltered.filter.Planify {
  case _ => ResponseString(
    "I can echo exactly one path element."
  )
}
unfiltered.jetty.Server.anylocal.plan(echo).plan(nice).run()

Happy now?

Plans and Intents 

Unfiltered conditionally handles incoming requests using partial functions. From the application’s perspective, requests are mapped to code paths by pattern matching. The library uses a particular vocabulary to refer to the agents of this process without ambiguity.

For example, the unfiltered.filter.Plan trait extends the javax.servlet.Filter interface. It declares an abstract intent method for clients to define the intent partial function.

Making Plans of Intents 

Looking back at the example on the previous page, you might wonder where the plan ends and the intent begins.

import unfiltered.request._
import unfiltered.response._
val echo = unfiltered.filter.Planify {
   case Path(Seg(p :: Nil)) => ResponseString(p)
}

In this case a plan is constructed directly from an anonymous partial function—that function is the intent. We can define the same plan in more explicit parts, as is usually necessary in a larger application.

object Echo extends unfiltered.filter.Plan {
  def intent = {
    case Path(Seg(p :: Nil)) => ResponseString(p)
  }
}

Since this kind of plan is an implementation of the servlet filter interface, we can pass it directly to a servlet container.

unfiltered.jetty.Server.anylocal.plan(Echo).run()

Passing on That 

Since an intent is a partial function, it may be undefined for a request. In this case the request may be handled by some other intent or it could produce a 404 error from the server.

Unfiltered also supports an explicit mechanism to specify that a matched request should not be handled by an intent: the Pass object.

  
object Public extends unfiltered.filter.Plan {
  def intent = {
    case Path(Seg("admin" :: _)) => Pass
    case Path(Seg(path :: Nil)) => myRenderer(path)
  }
}

This intent avoids handling anything under /admin by matching that condition and passing on it. There are other ways to achieve the same ends, but an explicit Pass is often the most straightforward.

Keep in mind that Scala’s partial functions are unaware of Unfiltered’s Pass mechanism, so the intent above is in fact defined for the excluded paths. But when attached to a plan, requests that evaluate to Pass are treated the same as those that are undefined.

Chaining Intents 

When you want to combine intents within a single plan, use onPass:

object MyPlan extends unfiltered.filter.Plan {
  def intent = publicIntent.onPass(privateIntent)

  val publicIntent = unfiltered.filter.Intent { ... }
  val privateIntent = unfiltered.filter.Intent { ... }
}

The onPass method is defined implicitly for PartialFunction with the import of the unfiltered.response._ package. It works like orElse but is aware of the Pass object and it’s optimized to avoid unnecessary reevaluation of pattern guards.

Bindings and Servers 

The core module unfiltered-library does not depend on or reference any particular server backend. It defines internal abstractions for requests and responses, with higher level abstractions on top.

An application or library that depends only on the core library could be used with any backend that Unfiltered supports, but in most cases it will depend on a binding module.

Binding Modules 

These bind Unfiltered’s generic request and response interfaces to a given implementation, as well as intent types and plan traits.

Servlet Filters (unfiltered-filter) 

The Java Servlet API enables you to write applications that run on servlet containers, anything from Tomcat to Google App Engine. Its plan trait is a servlet filter.

Asynchronous Servlet Filters (unfiltered-filter-async) 

Asynchronous Servlet Filters are using jetty-continuation under the hood which should provide a general purpose API that will work asynchronously on any servlet-3.0 container, as well as on Jetty 6, 7 or 8 (Continuations will also work in blocking mode with any servlet 2.5 container.)

object AsyncPlan extends unfiltered.filter.async.Plan  {
    def intent = { 
      case GET(UFPath("/pass")) => Pass
      case req@GET(UFPath("/async")) =>
        //"respond" is usually called from an asynchronous callback handler
        req.respond(ResponseString("test") ~> Ok) 
    }   
}
//then you can register this plan with jetty as usual
unfiltered.jetty.Server.http(8080).plan(AsyncPlan).run()

Note: Alternately, local(8080) binds to the loopback network interface only.

Netty Channel Handlers (unfiltered-netty) 

Netty defines channels for network I/O and implements them using Java’s Native I/O (NIO) interface. Its plan traits are upstream channel handlers, and the module defines intents and plans in separate cycle and async subpackages, the former for traditional request-response cycles and the latter for open-ended interaction.

Server Modules 

Server modules define runnable servers to execute your plans. They are entirely optional. Applications can instead use Unfiltered’s binding modules with external containers, or they can interface directly with server libraries.

unfiltered-jetty 

Includes builders for Jetty servers that implement the HTTP and HTTPS protocols. With this server it is particularly easy to serve a web browser interface for a local process. Unfiltered even gives you a shortcut to open a browser window, if the user is on a 1.6+ JVM that supports it.

import unfiltered.request._
import unfiltered.response._
val hello = unfiltered.filter.Planify {
  case _ => ResponseString("hello world")
}
unfiltered.jetty.Server.anylocal.plan(hello).run { s =>
  unfiltered.util.Browser.open(
    s.portBindings.head.url
  )
}

unfiltered-jetty-ajp 

A Jetty server configured for the Apache JServ Protocol, a binary protocol for proxying web requests.

unfiltered-netty-server 

Bootstraps and binds a server for your channel handlers.

import unfiltered.request._
import unfiltered.response._
val hello = unfiltered.netty.cycle.Planify {
  case _ => ResponseString("hello world")
}
unfiltered.netty.Server.http(8080).plan(hello).run()

Project Setup 

Modules and Artifacts 

Unfiltered’s core, binding, server, and other modules are published with references to their underlying dependencies, so that applications need only explicitly depend on Unfiltered and other top-level dependencies. Keep in mind that server modules and binding modules are not generally co-dependent, so that if you are using for example unfiltered-jetty, you will also need to specify unfiltered-filter.

Each module is cross-built against several versions of Scala and published to the sonatype repository with the organization-id “net.databinder”. The modules have the Scala version they are built against appended. For Scala 2.11+, the full artifact names are as follows:

Source Dependencies 

Some Unfiltered modules depend on external Scala libraries which are not cross-built across our supported versions of Scala. The overhead to produce binary artifacts for these modules is great, as we must maintain a map of Scala versions to compatible library versions, and also handle the case where there is no compatible version.

Instead we tag releases of these modules in github and encourage their use as source dependencies, which you may build locally against a compatible set of artifacts.

Build Tools 

Configuring sbt projects 

When using sbt with binary dependencies it’s best to have the Scala version automatically appended so it will always match your project’s. In an sbt 0.12.x project:

libraryDependencies += "net.databinder" %% "unfiltered-filter" % "0.8.4"

To use source dependencies with sbt, create a project build such as project/build.scala:

import sbt._
object MyApp extends Build
{
  lazy val root =
    Project("root", file(".")) dependsOn(unfilteredScalate)
  lazy val unfilteredScalate =
    uri("git://github.com/unfiltered/unfiltered-scalate#0.8.4")
}

Maven 

For Maven, specify the full artifact name:

<dependency>
  <groupId>net.databinder</groupId>
  <artifactId>unfiltered-filter_2.11</artifactId>
  <version>0.8.4</version>
</dependency>

To use source dependencies with Maven, your best bet is to check out the project as a submodule.

Template Projects 

For a new project the easiest the easiest option to apply a giter8 template for the Unfiltered backend of your choice.

So for example:

g8 n8han/unfiltered-netty --name=justplayin
cd justplayin
sbt # *or whatever your 0.11.x command is
> run

Community 

Unfiltered lives on GitHub, and many of its features and bug fixes originate in forks of the project there. We also have a mailing list.

Matching and Responding 

A typical request/response cycle can be handily directed with a few lines of code. This section applies pattern matching and combinator functions to expose a simple key-value store.

Request Matchers 

Methods and Paths 

Unfiltered supplies a wide range of request matchers—extractor objects that work against requests—from path segments to HTTP methods and headers. Applications use request matchers to define whether and how they will respond to a request.

case GET(Path("/record/1")) => ...

This case will match GET requests to the path /record/1. To match against path segments, we can nest one additional extractor:

case GET(Path(Seg("record" :: id :: Nil))) => ...

This matches any id string that is directly under the record path. The Seg extractor object matches against the String type and it is typically nested under a Path matcher. Seg extracts a lists of strings from the supplied string, separated into path segments by forward-slashes.

Reading Requests and Delayed Matching 

The above case clause matches a request to get a record. What about putting them?

case req @ PUT(Path(Seg("record" :: id :: Nil))) =>
  val bytes = Body.bytes(req)
  ...

Access to the request body generally has side effects, such as the consumption of a stream that can only be read once. For this reason the body is not accessed from a request matcher, which could be evaluated more than one time, but from utility functions that operate on the request object.

In this case, we assigned a reference to the request using req @ and then read its body into a byte array—on the assumption that its body will fit into available memory. That aside, a minor annoyance is that this code introduces some repetition in the matching expression.

case GET(Path(Seg("record" :: id :: Nil))) => ...
case req @ PUT(Path(Seg("record" :: id :: Nil))) => ...

An alternative is to match first on the path, then on the method:

case req @ Path(Seg("record" :: id :: Nil)) => req match {
  case GET(_) => ...
  case PUT(_) => ...
  case _ => ...
}

This approach eliminates the duplicated code, but it’s important to recognize that it behaves differently as well. The original intent partial function was simply not defined for request to that path that were not a GET or a PUT. The latest one matches any request to that path, and therefore it must return a value for all methods with its match expression.

Importantly, delaying the match on request method simplified the intent partial function. What used to be two cases is now one, and we could add support for other methods like DELETE without adding any complexity to its pattern matching. This is worth noting because ifDefined is called on every intent at least once prior to its evaluation. By making the intent more broadly defined, we’ve reduced the complexity of that and potentially improved runtime performance.

Within the Parameters 

Extracting Params 

Requests are commonly accompanied by named parameters, either in the query string of the URL or in the body of a POST. Unfiltered supports access to these parameters with the Params extractor.

import unfiltered.request._
import unfiltered.response._
val pEcho = unfiltered.filter.Planify {
  case Params(params) =>
    ResponseString(params("test").toString)
}

The type of params extracted is Map[String, Seq[String]], with a default value of Seq.empty. With this interface, it is always safe to apply the map. But keep in mind that parameters may be specified with no value, and may occur multiple times. The Params extractor returns empty strings for named parameters with no value, as many times in the sequence as they occurred in the request.

For example, the query string ?test&test=3&test produces the sequence of strings "", "3", "". You can check this yourself by querying the plan defined above:

unfiltered.jetty.Server.anylocal.plan(pEcho).run()

Routing by Parameter 

While the Params extractor is useful for accessing parameters, it doesn’t provide any control flow to an intent partial function.

If you want to route requests based on the parameters present, you’ll need to nest a custom extractor inside Params. For this Unfiltered provides a Params.Extract base class:

object Test extends Params.Extract("test", Params.first)

The above extractor will match on the first parameter named “test” in a request. If no parameters are named test, the pattern does not match. However, a named parameter with no value would match. We can exclude this possibility with a richer definition.

object NonEmptyTest extends Params.Extract(
  "test",
  Params.first ~> Params.nonempty
)

The second parameter of the Params.Extract constructor is a function Seq[String] => Option[B], with B being the type extracted. The values first and nonempty are functions defined in the Params object that may be chained together with ~> (as with response functions).

Typically the chain begins with first, to require at least one parameter of the given name and discard the rest. Subsequent functions may require a nonempty value as above, or produce a trimmed string, or an int value from the string.

When a parameter transformation function fails, None is produced and the extractor does not match for the request. Knowing this, you can write your own transformation functions using map and filter.

object NotShortTest extends Params.Extract(
  "test",
  Params.first ~> { p: Option[String] =>
    p.filter { _.length > 4 }
  }
)

There’s also a convenience function to simplify the definition of transformation predicates.

object NotShortTest2 extends Params.Extract(
  "test",
  Params.first ~> Params.pred { _.length > 4 }
)

Try it all out in this server, which returns 404 unless provided with a “pos” parameter that is a positive integer, and “neg” that is negative.

object Pos extends Params.Extract(
  "pos",
  Params.first ~> Params.int ~>
    Params.pred { _ > 0 }
)
object Neg extends Params.Extract(
  "neg",
  Params.first ~> Params.int ~>
    Params.pred { _ < 0 }
)
val intEcho = unfiltered.filter.Planify {
  case Params(Pos(pos) & Neg(neg)) =>
    ResponseString("%d %d".format(pos,neg))
}
unfiltered.jetty.Server.anylocal.plan(intEcho).run()

The & extractor matches when the extractor to its left and right match, in this case to require multiple parameters.

Response Functions 

Response Function and Combinators 

With a typical request-response cycle intent, the partial function’s return value is of Unfiltered’s type ResponseFunction. A response function takes a response object, presumably mutates it, and returns the same response object.

Unfiltered includes a number of response functions for common response types. Continuing the “record” example, in some cases we may want to respond with a particular string:

  case PUT(_) =>
    ...
    ResponseString("Record created")

We should also set a status code for this response. Fortunately there is a predefined function for this too, and response functions are easily composed. Unfiltered even supplies a chaining combinator ~> to make it pretty:

  case PUT(_) =>
    ...
    Created ~> ResponseString("Record created")

If we had some bytes, they would be as easy to serve as strings:

  case GET(_) =>
    ...
    ResponseBytes(bytes)

Passing or Handling Errors 

And finally, for the case of unexpected methods we have a few choices. One option is to pass on the request:

  case _ => Pass

The Pass response function is a signal for the plan act as if the request was not defined for this intent. If no other plan responds to the request, the server may respond with a 404 eror. But we can improve on that by ensuring that any request to this path that is not an expected method receives an appropriate response:

  case _ => MethodNotAllowed ~>
              ResponseString("Must be GET or PUT")

Silly Store 

Opening the Store 

Using the request matchers and response functions outlined over the last couple of pages, we have everything we need to build a naive key-value store.

import unfiltered.request._
import unfiltered.response._

object SillyStore extends unfiltered.filter.Plan {
  @volatile private var store = Map.empty[String, Array[Byte]]
  def intent = {
    case req @ Path(Seg("record" :: id :: Nil)) => req match {
      case GET(_) =>
        store.get(id).map(ResponseBytes).getOrElse {
          NotFound ~> ResponseString("No record: " + id)
        }
      case PUT(_) =>
        SillyStore.synchronized {
          store = store + (id -> Body.bytes(req))
        }
        Created ~> ResponseString("Created record: " + id)
      case _ =>
        MethodNotAllowed ~> ResponseString("Must be GET or PUT")
    }
  }
}

Go ahead and paste that into a console. Then, execute the plan with a server, adjusting the port if your system does not have 8080 available.

unfiltered.jetty.Server.local(8080).plan(SillyStore).run()

The method local, like anylocal, binds only to the loopback interface, for safety. SillyStore is not quite “web-scale”.

Curling the Store 

The command line utility cURL is great for testing HTTP servers. First, we’ll try to retrieve a record.

curl -i http://127.0.0.1:8080/record/my+file

The -i tells it to print out the response headers. Curl does a GET by default; since there is no record by that or any other name it prints out the 404 response with our error message. We have to PUT something into storage.

echo "Ta daa" | curl -i http://127.0.0.1:8080/record/my+file -T -

Curl’s option -T is for uploading files with a PUT, and the hyphen tells it to read the data piped in from echo. Now, we should have better luck with a GET request:

curl -i http://127.0.0.1:8080/record/my+file

That worked, right? We should also be able to replace items:

echo "Ta daa 2" | curl -i http://127.0.0.1:8080/record/my+file -T -
curl -i http://127.0.0.1:8080/record/my+file

And lastly, test the method error message:

curl -i http://127.0.0.1:8080/record/my+file -X DELETE

405 Method Not Allowed. But it’s a shame, really. DELETE support would be easy to add. Why don’t you give it a try?

Directives and Validation 

Pattern matching is an easy and reliable way to handle requests that conform to expected criteria, but what about the requests that don’t? Typically, they fall through to a 404 handler. While this behavior is logical enough from the perspective of a service’s programming, clients of the service might reasonably assume that they’ve supplied the wrong path instead of, as in a previous example, an invalid parameter.

With enough fallback cases and nested match expressions, you could program whatever logic you want — including descriptive error handling. But that approach sacrifices the simplicity and readability that made pattern matching attractive in the first place.

Fortunately, there is another way. With directives you can express request criteria concisely, and scrupulously handle errors too.

Directive Intent 

Within an Unfiltered plan, an intent function maps from request objects to response functions. With directives, you define a partial function mapping from requests to a Result. We compose this function with another, which produces the standard intent function understood by Unfiltered.

Directives are an example of an Unfiltered kit, set of tools providing a higher level of abstraction over the core library.

Selective enforcement 

You can define a directive function using familiar request extractors. Let’s start with a raw intent function.

import unfiltered.request._
import unfiltered.response._

val Simple = unfiltered.filter.Planify {
  case Path("/") & Accepts.Json(_) =>
    JsonContent ~> ResponseString("""{ "response": "Ok" }""")
}
unfiltered.jetty.Server(8080).plan(Simple).run()

You can use curl to inspect the different responses:

curl -v http://localhost:42490/ -H "Accept: application/json"
curl -v http://localhost:42490/

The 404 response page to the second request is not so great. With directives, we’ll do better than that by default.

import unfiltered.directives._, Directives._

val Smart = unfiltered.filter.Planify { Directive.Intent {
  case Path("/") =>
    for {
      _ <- Accepts.Json
    } yield JsonContent ~> ResponseString("""{ "response": "Ok" }""")
} }
unfiltered.jetty.Server(8080).plan(Smart).run()

And with that you’ll see a 406 Not Acceptable response when appropriate.

Directives results are typically, but not necessarily, defined in a single for expression. In the expression above we discard the result value of the Accepts.Json directive, as we did previously with the extractor, and map it to our dummy response function.

The 406 error response is produced by the directive itself, encapsulating behavior that can be used everywhere. What if you want different error behavior? Make your own directive! (Seriously, you’ll see how on the next page.)

One true path 

You may have noticed that directives transfer (and enrich) routing logic from extractors. If your extractors are reduced to the task of matching against paths alone, you can even eliminate those.

val Sweet = unfiltered.filter.Planify { Directive.Intent.Path {
  case "/" =>
    for {
      _ <- Accepts.Json
    } yield JsonContent ~> ResponseString("""{ "response": "Ok" }""")
} }
unfiltered.jetty.Server(8080).plan(Sweet).run()

It looks pretty different, but remember that here still composes to a standard Unfiltered intent function.

Parameters as Directives 

Any part of a request can be used to route and accept or reject the request. Request parameters, encoded in a query string or a POST request body, are an open field for richer requests — and user error. We can handle these with directives as well.

Parameters Values 

In HTTP, a parameter key can be specified multiple times with different values. Unfiltered’s base model for parameters is therefore a string key to a sequence of string values in the order they were supplied. This is easy to obtain in a directive.

import unfiltered.request._
import unfiltered.response._
import unfiltered.directives._, Directives._

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        in <- parameterValues("in")
      } yield ResponseString(in.toString)
  } }
).run()

You can try this service with multiple, one, or no parameters.

curl -v http://127.0.0.1:8080/ -d in=one -d in=two

Even with no parameters, the directive succeeds with an empty sequence. Since it’s not establishing control flow, we could have accessed it just as easily through the Params map. But typically, we do have requirements on our input.

I’m thinking of a Number 

Things get more interesting when require parameters to be in a particular format. From here on out, we’ll be working with interpreters in the unfiltered.directive.data package. Interpreters define abstract operations on data; we can produce directives for a particular request parameter with named.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        in <- data.as.Int named "in"
      } yield ResponseString(in.toString)
  } }
).run()

By testing this service you’ll find that all requests to the root path are accepted, and that the in value is bound to an Option[Int]. If an in request parameter is not present or not a valid int, the value is None. This is a directive, but it’s still one that always produceses a Success result.

What about repeated parameters? The object data.as.Int is an interpreter from String to Int, but in HTTP we model parameter values as a sequence of strings. This gap is bridged by another interpreter data.as.String, which chooses the first in the sequence. It’s applied implicitly when needed.

We can transform an interpreter that ignores failed interpretation into one that produces a failure response by passing an error handler to its fail method.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        in <- data.as.Int.fail { (k,v) =>
          BadRequest ~> ResponseString(
            s"'$v' is not a valid int for $k"
          )
        } named "in"
      } yield ResponseString(in.toString)
  } }
).run()

The error handling function receives both the parameter name and given value as parameters. This way, a directive used for more than one parameter can have a specific error message for each.

Interpreter Reuse and Implicits 

Explicit Interpreters 

In a non-trival application you are likely to have more than one parameter of one method that expects an integer. Instead of defining interpreters inline, as in previous examples, you can define a general interpreter once and use it many places.

import unfiltered.request._
import unfiltered.response._
import unfiltered.directives._, Directives._

val intValue = data.as.Int.fail { (k,v) =>
  BadRequest ~> ResponseString(
    s"'$v' is not a valid int for $k"
  )
}

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        a <- intValue named "a"
        b <- intValue named "b"
      } yield ResponseString(
        (a ++ b).sum + "\n"
      )
  } }
).run()

In the example above we explicitly reference and apply a single interpreter to parameters “a” and “b”, responding with their sum.

Unclear on the summing step? Values a and b are both of the iterable type Option[Int]. We join these with ++ forming a sequence of integers that could be as long as 2 or as short as 0, depending on the input. The sum method on this sequence does what you’d expect, and finally we join with a string.

Implicit Interpreters 

Referencing an interpreter was fairly tidy operation, but as we’ll be using interpreters often and in different applications, naming and recalling names for various types could become tedious. Let’s try it with an implicit.

implicit val implyIntValue =
  data.as.String ~> data.as.Int.fail { (k,v) =>
    BadRequest ~> ResponseString(
      s"'$v' is not a valid int for $k"
    )
  }

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        a <- data.as.Option[Int] named "a"
        b <- data.as.Option[Int] named "b"
      } yield ResponseString(
        (a ++ b).sum + "\n"
      )
  } }
).run()

The first thing you may notice is that implyIntValue is a bit wordier than its predecessor. An implicit interpreter used for request parameters must interpret from Seq[String]. Think of it as a full interpretation from the input format to the output type. You may define these for any output types you want, and import them into scope wherever you want to use them. Interpreters like response functions can be chained with ~>, and so data.as.String is typically used at the beginning of an interpreter to be used implicit.

If it seems like extra work to define implicit interpreters, keep reading. The payoff comes with required parameters.

Required Parameters 

So far we’ve learned know how to define implicit interpreters from a sequence of string to any type T and use them with data.as.Option[T]. Now we’ll see how to use the same interpreters for required parameters.

Your “required” Function 

The failure to supply a required parameter must produce an application defined error response. We’ll define a very simple one.

import unfiltered.request._
import unfiltered.response._
import unfiltered.directives._, Directives._

implicit def required[T] = data.Requiring[T].fail(name => 
  BadRequest ~> ResponseString(name + " is missing\n")
)

The name of the function is not important when used implicitly, but call it required is a good convention since you may also want to use it explicitly when defining interpreters inline.

Using “required” Implicitly 

With a required function in scope we can use it with any implicit interpreters also in scope. The data.as.String interpreter is imported from the Directives object, so we can use it immediately.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        opt <- data.as.Option[String] named "opt"
        req <- data.as.Required[String] named "req"
      } yield ResponseString(
        s"opt: $opt req: $req"
      )
  } }
).run()

Let’s examine the output from this one with curl:

$ curl -v http://127.0.0.1:8080/ -d opt=hello -d req=world
opt: Some(hello) req: world

Since req is required to produce a success response, it’s not wrapped in Option or anything else; the type of the bound value is whatever its interpreter produces.

Using “required” Explicitly 

Most interpreters work with an option of the data so that they can be chained together in support of both optional and required parameters. Required is itself an interpreter which unboxes from the Option, so it generally must be the last interpreter in a chain.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        in <- data.as.BigInt ~> required named "in"
      } yield ResponseString(
        in % 10 + "\n"
      )
  } }
).run()

This service returns the last digit of the required provided integer. Since we didn’t provide a fail handler for data.as.BigInt, it falls to required to produce a failure response.

$ curl http://127.0.0.1:8080/ -d in=1334534
4
$ curl http://127.0.0.1:8080/ -d in=1334534a
in is missing

To be more specific, we can supply a failure to the integer interpreter.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        in <- data.as.BigInt.fail((k,v) => 
          BadRequest ~> ResponseString(s"'$v' is not a valid int for $k\n")
        ) ~> required named "in"
      } yield ResponseString(
        in % 10 + "\n"
      )
  } }
).run()

Now each failure condition produces a distinct error.

$ curl http://127.0.0.1:8080/ -d in=1334534a
'1334534a' is not a valid int for in
$ curl http://127.0.0.1:8080/
in is missing

Independent Failure 

A request that is mapped through a directive can produce either a failure or success response. Usually, this works the way you want. When a PUT request is received for an endpoint that only supports POST, the service can respond with a 405 MethodNotAllowed status without inspecting parameters any request parameters.

But among the request parameters themselves, it may be desirable to respond with multiple error messages when there are multiple parameters in error. This can be accomplished by combining directives into a single directive which knows how to bundle the error responses.

Normalizing Error Responses 

Even if you don’t intend to bundle errors right away, it’s a good idea to generate error responses in a consistent way. This allows you to factor out the status code generation and to put error messages in context. One way to do this is with a case class.

import unfiltered.request._
import unfiltered.response._
import unfiltered.directives._, Directives._

case class OneBadParam(msg: String) extends Responder[Any] {
  def respond(res: HttpResponse[Any]): Unit = 
    (BadRequest ~> ResponseString(msg + "\n"))(res)
}

We could use this class with a “required” function.

implicit def required[T] = data.Requiring[T].fail(name => 
  OneBadParam(name + " is missing")
)

This cuts out a bit of boiler plate, but things get more interesting when we define a smarter case class.

Joinable Responses 

If we want Unfiltered to combine error responses from multiple directives, we need to specify exactly how that should work. This can be done with a simple variation of the case class defined above.

case class BadParam(msg: String) extends ResponseJoiner(msg)(
  msgs =>
    BadRequest ~> ResponseString(msgs.mkString("","\n","\n"))
)

Instances of this class are still defined for a single error message msg, but they know how to format a response for multiple messages of the same type. This allows the toolkit to combine many BadParam instances into a single error response, using the response function defined on any one of the instances.

The type system guarantees that error messages are of the same type and that any instance can produce a response from them, but it is not guaranteed which instance’s error handler will be used to produce the error response. You should use the same case class, or the same error handling function, for all of your response error instances.

We can redefine “required” with this improved error responder.

implicit def required[T] = data.Requiring[T].fail(name => 
  BadParam(name + " is missing")
)

Joining and Splitting Directives 

Now that we have joinable error responses issued from our required interpreter, we can use the & method of Directive to join them, as well as an unapply method of unfiltered.request.& to split them.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        (a & b & c) <-
          (data.as.Required[String] named "a") &
          (data.as.Required[String] named "b") &
          (data.as.Required[String] named "c")
      } yield ResponseString(
        s"a: $a b: $b c: $c"
      )
  } }
).run()

In a failure case, the errors objects are combined and returned on separate lines. On success, the combined directive produces nested tuples of the success cases which & extracts in the order produced.

$ curl http://127.0.0.1:8080/
a is missing
b is missing
c is missing

Interpreters of Your Own Design 

Unfiltered comes with a small number of interpreters for standard Scala types. We may have left out the one you want (send a pull request), or perhaps you’d like to define interpreters for a type specific to your own application. This is in fact a very good idea!

Conditional Interpreters 

A simple way to augment an interpreter is to require a condition for which it is valid. For example, in your application valid identifiers might be non-negative, non-zero integers up to a certain size. Another application might permit a certain set of characters as identifiers.

Rather than attempting to anticipate all the ways you might like to constrain input parameters, Unfiltered leaves it to you to define interpreters using the Scala language. Here, we’ll define a simple one that accepts only even integers.

import unfiltered.request._
import unfiltered.response._
import unfiltered.directives._, Directives._

def badParam(msg: String) =
  BadRequest ~> ResponseString(msg)

val evenInt = data.Conditional[Int](_ % 2 == 0).fail(
  (k, v) => badParam("not even: " + v)
)

As a conditional interpreter of integer, evenInt inputs and outputs an integer, failing with an error if it doesn’t satisfy the condition. To make it work seamlessly with request parameters we may define an implicit integer interpreter.

implicit val intValue =
  data.as.String ~> data.as.Int.fail(
    (k, v) => badParam("not an int: " + v)
  )

Then it’s just a matter of using evenInt like any other interpreter.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        even <- evenInt named "even"
      } yield ResponseString(
        even + "\n"
      )
  } }
).run()

Fallible Interpreters 

Conditional interpreters are great for adding application-specific constraints to existing interpreters, but often you’ll need to create interpreters for your own types. These are known as fallible interpreters, under the assumption that any conversion may fail.

You can make a fallible interpreter to any type. We’ll demonstrate with a simple typed data store.

case class Tool(name: String)
val toolStore = Map(
  1 -> Tool("Rock"),
  2 -> Tool("Paper"),
  3 -> Tool("Scissors")
)

val asTool = data.Fallible[Int,Tool](toolStore.get)

implicit def implyTool =
  data.as.String ~> data.as.Int ~> asTool.fail(
    (k, v) => badParam("'$v' is not a valid tool identifier")
  )

The data.Fallible case class takes a function from its input type to an option of its output type; Map#get fits the bill perfectly. Then we defined a complete, error-capable interpreter so that it’s easy and clean to turn input parameters into tools.

unfiltered.jetty.Server(8080).plan(
  unfiltered.filter.Planify { Directive.Intent {
    case Path("/") =>
      for {
        tool <- data.as.Option[Tool] named "id"
      } yield ResponseString(
        tool + "\n"
      )
  } }
).run()

Let’s see how it works:

curl http://127.0.0.1:8080/  -d id=3
Some(Tool(Scissors))

With a parameter directive you can interpret the input into any type you like. We used an in-memory map, but it could just as easily be an entity loaded from external storage.

Let’s wrap this up, Ada 

We’ve seen how to use directives in general, and how to use interpreters to make our own parameter directives, and even how to make our own interpreters. Our closing example will be one that you’ve had with you all along: the default Unfiltered giter8 template.

Setting up the Template 

If you don’t have the template project already, skip back to the beginning and follow the directions up until the Consoled section.

Instead of entering a Scala console this time, we want to examine and use the Scala sources included in the project. Go ahead and compile and run them:

sbt run

The main class in the project will start an HTTP server on some available port, and it will attempt to open the root document on that server in your default browser. If you see a big ugly form, you’re all set.

Understanding the Source 

Take a look at the source for the server, located here:

src/main/scala/Example.scala

You should be able to understand most of what’s happening, but there are a few things worth mentioning. Unlike previous examples in this chapter, this is a web server intended for browser clients. Our output is HTML and our input for the POST is a form serialized by the browser.

A simple view function is defined for displaying the page in both its initial, error, and success states. The function takes a map of parameters so that it can serve back the form inputs exactly as they were submitted, without being affected by any interpreters. We can get this separately from our parameter directives, using the trusty old Params extractor.

Since we’re just calling out snippets of the code, you won’t be able to copy and paste these into a console as you can with most sections of this documentation. Feel free to play around with the template project source though, that’s what it’s there for.

    case POST(Params(params)) =>
      case class BadParam(msg: String)
      extends ResponseJoiner(msg)( messages =>
          view(params)(<ul>{
            for (message <- messages)
            yield <li>{message}</li>
          }</ul>)
      )

Also worth noting is that we defined our BadParam case class inside the match expression, since it needs a reference to params to build its error response. Another option would have been to take the params as a constructor parameter for the class.

Finally, since we’re dealing with user input via a serialized form rather than a programmatic web service, our expectations for errors are different. An “empty” field in the form is still submitted as a parameter — an empty string. Since this will be a common user error, we should handle it much like we would if the parameter were not submitted at all.

val inputString = data.as.String ~>
  data.as.String.trimmed ~>
  data.as.String.nonEmpty.fail(
    (key, _) => BadParam(s"$key is empty")
  )

But of course, we still need to define a required function since it is possible that some client will fail to submit a parameter.

implicit def required[T] = data.Requiring[T].fail(name =>
  BadParam(name + " is missing")
)

Finally, in this case the code keeps the logic of the conditional interpreter separate from the implementation, which is inline.

(inputString ~> data.Conditional(palindrome).fail(
  (_, value) => BadParam(s"'$value' is not a palindrome")
) ~> required named "palindrome")
...
def palindrome(s: String) =
  s.toLowerCase.reverse == s.toLowerCase

This is just to show the variety of what’s possible, it’s up to you to decide how to organize and apply your own interpreters. Good luck, and don’t be shy about contributing back interpreters of standard library types back into the Unfiltered directives source!

Application Structure 

The previous section showed how to respond to requests using a simple intent function. The building blocks of Unfiltered are easy to grasp, but how do you build a much larger application with them?

The short answer is, by using Scala. Unfiltered does not impose idioms on your application structure, it’s just an HTTP translation layer to be applied as you see fit.

That said, partial functions are not the most common entry point for web applications and their heavy use in this context may disorient the beginner. This section explores some logical structures to put you on the path to determining your own application design.

Planning for Any-thing 

Thanks to one of the darker corners of the Scala type system (variance), it’s a cinch to define intents that work with all plans.

Agnostic Intents 

import unfiltered.request._
import unfiltered.response._

object Hello {
  val intent = unfiltered.Cycle.Intent[Any, Any] {
    case _ => ResponseString("Hello")
  }
}

The object Hello defines an intent with underlying request and response types of Any. As a result, the intent can not statically expect a particular underlying request or response binding. This makes sense, as we want to make an intent that works with any of them.

Specific Plans 

The next step is to supply the same generic intent to different kinds of plans.

val helloFilter =
       unfiltered.filter.Planify(Hello.intent)

val helloHandler =
       unfiltered.netty.cycle.Planify(Hello.intent)

As usual the plans are actual servlet filters or Netty handlers, so you could use them with a server you have configured separately or with a server configured by Unfiltered.

Just Kitting 

Unfiltered gives you many extractors to facilitate pattern matching, and it might be helpful to create some extractors specific to an application, but often you want to factor-out broader functionality. That’s where kits come in.

The GZip Kit 

We first had the idea for kits when considering how best to support GZip response encodings. An extractor to match an Accept-Encoding header for gzip would help, and a ResponseFunction to compress the response stream, but these would have to be repeated for every case expression.

The GZip kit is a higher level abstraction that can be applied at once to full intent function. The kit will examine the request first, and if appropriate, prepends a compressing function to the response function chain provided by the intent.

GZip Kit Definition 

This part is already done for you in unfiltered-libary, but in case you are curious this is how the GZip kit is defined.

object GZip extends unfiltered.kit.Prepend {
  def intent = Cycle.Intent[Any,Any] {
    case Decodes.GZip(req) =>
      ContentEncoding.GZip ~> ResponseFilter.GZip
  }
}

Unlike a plan’s intent function, this one defines the conditions for which its response function is prepended another intent’s. It sets a header and a FilterOutputStream for the response.

GZip Usage 

This is a very simple plan that will compress its responses if the user-agent supports it:

object EchoPlan extends unfiltered.filter.Plan {
  def intent = unfiltered.kit.GZip {
    case Path(path) => ResponseString(path)
  }
}

Do Kit Yourself 

The higher level abstraction provided by kits can be applied to problems specific to an application just as well as for general problems. Don’t be afraid to experiment, and if you happen to make something that does solve a general problem, please share it!

Identification and Cookies 

When remote users are humans interacting with web browsers, applications are often concerned with their identity and preferences. This section covers relevant interfaces defined for HTTP.

Who’s Who 

Out of the box HTTP provides you with basic authentication, a simple way to specify a name and password for a request. These credentials are transferred as an unencrypted request header, so applications should secure both credentials and message bodies by requiring HTTPS for any protected resources.

Below, we define a kit that extracts a username and password via basic HTTP authentication and verifies those credentials before letting anyone through the gate. It presumes a Users service that would validate the user’s credentials.

trait Users {
  def auth(u: String, p: String): Boolean
}

import unfiltered.request._
import unfiltered.response._
import unfiltered.Cycle

case class Auth(users: Users) {
  def apply[A,B](intent: Cycle.Intent[A,B]) =
    Cycle.Intent[A,B] {
      case req@BasicAuth(user, pass) if(users.auth(user, pass)) =>
        Cycle.Intent.complete(intent)(req)
      case _ =>
        Unauthorized ~> WWWAuthenticate("""Basic realm="/"""")
    }
}

By applying this kit we can layer basic authentication around any intent in a client application.

case class App(users: Users) extends
unfiltered.filter.Plan {
  def intent = Auth(users) {
    case _ => ResponseString("Shhhh!")
  }
}

Also, don’t give the password to any newspaper reporters.

Remembrance of Things Past 

Basic authentication is a lightweight solution to general authentication, but what if we need to remember a little more information about a user’s session? That’s where cookies come in.

Let’s build on our authenticated application and add support for simple cookie handling.

import unfiltered.Cookie

case class App(users: Users) extends
unfiltered.filter.Plan {
  def intent = Auth(users) {
    case Path("/") & Cookies(cookies) =>
      ResponseString(cookies("pref") match {
        case Some(Cookie(_, pref, _, _, _, _)) =>
          "you pref %s, don't you?" format pref
        case _ => "no preference?"
      })
    case Path("/prefer") & Params(p) =>
       // let's store it on the client
       ResponseCookies(Cookie("pref", p("pref")(0))) ~>
         Redirect("/")
    case Path("/forget") =>
       ResponseCookies(Cookie("pref", "")) ~>
         Redirect("/")
  }
}

Now that we have a slightly more sophisitcated basic application let’s mount it with a user named jim and a password of j@m.

object JimsAuth extends Users {
  def auth(u: String, p: String) =
    u == "jim" && p == "j@m"
}
unfiltered.jetty.Server(8080).plan(
  App(JimsAuth)
).run

In your browser, open the url http://localhost:8080/ and you should be greeted with its native authentication dialog. Enter jim and j@m, if you are feeling authentic.

Once authenticated you should see simple text questioning your preferences. Why is this? Well, you have yet to tell the server what you prefer. In your url bar, enter the address

http://localhost:8080/prefer?pref=kittens

or whatever else you have a preference for. Now, every time you request http://localhost:8080/ the server has remembered your preference for you. This is a cookie at work!

If you change your mind you can always hit the prefer path with a new pref or just tell the server to forget it by entering the address http://localhost:8080/forget.

Netty Plans 

Unfiltered’s interfaces to Netty reflect the lower-level nature of Netty as compared to Servlet Filters. This gives greater flexibility and power to the application, necessarily requiring greater responsibility and attention to detail by the programmer. If you’re up for the challenge or just want to play with something new, then give it a whirl.

Trying Netty 

As with the Jetty server used for earlier console hacking, for Netty we also need a starter project. If you don’t have the g8 command line tool installed, please go back to that page until you do.

Enter the Console 

This step will fetch a number of dependencies and sometimes certain repositories are a little wonky, so cross your fingers.

g8 unfiltered/unfiltered-netty --name=nettyplayin
cd nettyplayin
sbt console

Once you do get to a console, this should just work:

import unfiltered.request._
import unfiltered.response._
val hello = unfiltered.netty.cycle.Planify {
   case _ => ResponseString("hello world")
}
unfiltered.netty.Server.http(8080).plan(hello).run()

Direct a web browser to http://127.0.0.1:8080/ and you’ll be in hello world business.

Execution and Exceptions 

That’s pretty nifty how we started up a Netty server in a few lines of code, just like with Jetty, right? But while Planify is really handy for experimenting in the console, it makes a lot of assumptions that are unlikely to hold for a live server.

A Less Simple Plan 

Let’s see what the plan looks like with those defaults made explicit.

import unfiltered.netty._

trait MyPlan extends cycle.Plan with
cycle.ThreadPool with ServerErrorResponse

Object Hello extends MyPlan {
  def intent = {
    case _ => ResponseString("hello world")
  }
}

The traits define methods needed by cycle.Plan. But what for?

Deferred Execution 

Netty handlers are invoked on an I/O worker thread. In some scenarios (including this one, actually) it would be just fine to prepare a response on this thread. If the work is CPU-bound (does not perform blocking operations), you can mix in the cycle.SynchronousExecution trait instead, for no-overhead execution.

But a typical web application does need to access a database or something, and the typical way to do this is with a blocking call. That’s why Planify uses the cycle.ThreadPool trait, which defers application of the intent partial function to a cached thread pool.

Deference has its Memory Limits 

Unfortunately, that’s not the end of the story with deferred execution. Applications also need to worry about running out of memory. If you defer request handling jobs to an executor queue as fast as Netty can accept requests, any heap limit can be exceeded with a severe enough usage spike.

To avoid that kind of failure, you should equip your plans with an executor that consumes a limited amount of memory and blocks on incoming requests when that limit is reached. If you’ve defined a simple local base plan (like the MyPlan above), you can customize it later (ideally, before your server throws an out of memory exception) with with a memory-aware thread pool executor.

trait MyPlan extends cycle.Plan with
cycle.DeferralExecutor with cycle.DeferredIntent with
ServerErrorResponse {
  def underlying = MyExecutor.underlying
}
object MyExecutor {
  import org.jboss.netty.handler.execution._
  lazy val underlying = new MemoryAwareThreadPoolExecutor(
    16, 65536, 1048576)
}

Expecting Exceptions 

The ServerErrorResponse trait also implements behavior that your application will likely need to customize, sooner or later. Instead of mixing in that trait, you can implement onException directly in your base plan. For a starting point see the source for the provided exception handler, which logs the stack trace to stdout and serves a very terse error response. Normally an application will hook into its own logger and serve a custom error page or redirect.

Chunked Requests 

If you’re handling HTTP POSTs, it’s very possible that your browser or non-browser clients will send requests using chunked transfer encoding. This part of HTTP 1.1 is great for keeping messages short, but not so great for short short and simple NIO servers.

An Inconvenient Party Line 

The challenge for your server, as it is handling many concurrent requests, is to maintain the state of a message that is split into many chunks. For example if the request body contains url-encoded parameters, you must assemble all the chunks together to have uniform access to any parameter.

Netty provides a simple solution for cases like this: its HttpChunkAggregator assembles chunks into a single message. The caveat is that the full message is necessarily loaded into memory, and it could be arbitrarily large. The interface therefore requires you to chose a limit for the aggregated message size; any chunked request that exceeds this limit will raise a TooLongFrameException. (For general file upload support, see the netty-uploads module.)

Unfiltered’s Netty server-builder provides a convenient chunked interface for adding aggregating handlers to your pipeline:

unfiltered.netty.Server(8080).chunked(1048576).plan(hello).run()

If you want quick, easy, and limited support for chunked requests, don’t forget to call this method on your server builder.

Going Asynchronous 

While the cycle.Plan gives us the means to implement a traditional request-response cycle, with unfiltered-netty you also have the option to respond asynchronously to the request. When used with other asynchronous libraries, this can result in more efficient use of threads and support for more simultaneous connections.

Other Asynchronous Libraries 

Luckily, the “nettyplayin” project created in the last few pages already depends on a second asynchronous library, dispatch-nio, which acts as client for HTTP requests to other services. Using an async.Plan with dispatch.nio.Http, we can query other HTTP services to satisfy a request without hoarding a thread for the many milliseconds it could take to perform that request.

Always Sunny in… 

Google has a secret weather API. Let’s use that until they take it offline.

import dispatch._
val h = new nio.Http
def weather(loc: String) =
  :/("www.google.com") / "ig/api" <<? Map(
    "weather" -> loc)

Paste that into a console, then you can print the response like this:

h(weather("San+Francisco") >- { x => println(x) })

You may notice that the prompt for the next command appears before the response is printed. It’s working!

Taking the Temperature 

Now all we have to do is consume this service from a server.

import unfiltered.response._
import unfiltered.netty._

val temp = async.Planify {
  case req =>
    h(weather("San+Francisco") <> { reply =>
      val tempC = (reply \\ "temp_c").headOption.flatMap {
        _.attribute("data") 
      }.getOrElse("unknown")
      req.respond(PlainTextContent ~>
                  ResponseString(tempC + "°C"))
    })
}

Http(8080).plan(temp).run()

Pasting all that into a console should start up a server that always gives you the temperature in San Francisco (the closest city by that name to Google’s headquarters, anyway). When you are done with this hardcoded showpiece, shut down the Dispatch executor it was using so we can move on real deal.

h.shutdown()

Asyncrazy Temperature Server 

Putting this all together, we can build a server that would very efficiently get your IP address banned by Google if you actually put it on the web. But it’s totally cool to run it locally. We think.

import dispatch._
import unfiltered.request._
import unfiltered.response._
import unfiltered.netty._

object Location extends 
Params.Extract("location", Params.first ~> Params.nonempty)

object Temperature extends async.Plan with ServerErrorResponse {
  val http = new nio.Http
  def intent = {
    case req @ GET(_) =>
      req.respond(view("", None))
    case req @ POST(Params(Location(loc))) =>
      http(:/("www.google.com") / "ig/api" <<? Map(
        "weather" -> loc) <> { reply =>
          val tempC = for {
            elem <- reply \\ "temp_c"
            attr <- elem.attribute("data") 
          } yield attr.toString
          req.respond(view(loc, tempC.headOption))
        }
      )
  }
  def view(loc: String, temp: Option[String]) = Html(
    <html>
      <body>
        <form method="POST">
          Location:
          <input value={loc} name="location" />
          <input type="submit" />
        </form>
        { temp.map { t => <p>It's {t}°C in {loc}!</p> }.toSeq }
      </body>
    </html>
  )
}

Put all that into a console, then start it:

Http(8080).chunked(1048576).plan(Temperature).run()

You can lookup the current temperature for almost anywhere; just type in a place name or postal code and Google will probably figure it out.

When you are done checking the temperature of exciting places around the world, shutdown the handler’s Dispatch executor.

Temperature.http.shutdown()

Jetty Extras 

Serving Resources from a relative path 

Sometimes you may want to serve resources from a relative path, for example a sibling directory located at ../client. But paths containing .. are considered aliased and Jetty disallows these by default, as described in this policy.

If you’ve evaluated the security risks described in the link above and wish to enable aliases in paths, you can do so with allowAliases(true), eg:

unfiltered.jetty.Server.http(8080).
      context("/client"){ ctx: ContextAdder =>
      ctx.resources(new java.net.URL(
        """file:../client"""
      )).allowAliases(true)
      }.plan(myPlan).run()

Enabling Request Logs 

Jetty can be configured to log all requests in Common or Extended formats with requestLogging. This is a global, not per-context, setting. At minimum you need to specify where to log to:

unfiltered.jetty.Server.http(8080).plan(myPlan).requestLogging("/tmp/access.log").run()

Who’s Using Unfiltered? 

These are some projects and companies that have used Unfiltered. Are you using Unfiltered? Fork this page on github.

Meetup 

Unfiltered, Netty, and RabbitMQ run Meetup’s real-time APIs.

Novus 

Entire web layer of the Novus real-time financial analytics platform has been built by maxaf using Unfiltered. We have a myriad custom request unapplies and use Scalate extensively. There’s no better way to express web application concerns than using Scala idioms. High engineer productivity and type safety have contributed a lot to our product’s bottom line.

Remember The Milk 

Unfiltered is used in Remember The Milk’s public API, real time updates and syncing endpoints for Android, iOS and Outlook.

Trust Metrics 

Trust Metrics uses Unfiltered everywhere. We use it in our API, our client facing app, our intranet, and even our web crawler. We use it because it’s simple and nonintrusive—it lets us decide how to add web to our app, unlike other frameworks (Grails/Rails/Django), which do all of the deciding for you.

EAT.PRAY.MOVE 

EAT.PRAY.MOVE organizes, facilitates, and instructs yoga retreats in Italy and other Mediterranean areas. This is a simple crud website hosted on Google App Engine using Scalate for templating and highchair for persisting scala objects to the Google data store. Unfiltered runs the show.

lssn.me 

lssn.me is a simple URL shortening service hosted on Google App Engine. Unfiltered services the requests and highchair handles persistence.

nescala.org 

The event site for the North East Scala Symposium is written using Unfiltered’s filter plans and hosted on Google App Engine.

pamflet 

The documentation preview server in pamflet is Unfiltered.

picture show 

Self-contained slide-show presentations authored in basic markdown, served in html and css served by Unfiltered.

scalaxb 

scalaxb-appengine is an Unfiltered API to run scalaxb over the web on appengine.

unplanned 

A super simple run anywhere adhoc HTTP server using conscript and the Unfiltered jetty module.

penger.no 

penger.no is a Norwegian web based service whose aim is to help consumers compare the prices and terms of bank and insurance providers to find the best offer.

Fork me on GitHub