Mustache Integration with HTTP Routing

Mustache support for HTTP servers is provided by the finatra/http-mustache library. This integrates Finatra’s general Mustache support with Finatra’s HTTP MessageBodyComponents.

You must include the c.t.finatra.http.modules.MustacheModule in your server’s list of modules in order for the framework to negotiate rendering of Mustache templates via MessageBodyComponents.

import com.google.inject.Module
import com.twitter.finatra.http.modules.MustacheModule
import com.twitter.finatra.http.HttpServer

class MyServer extends HttpServer {
    override val modules: Seq[Module] = Seq(MustacheModule)

    ???
}

The c.t.finatra.http.modules.MustacheModule includes the general MustacheFactoryModule which is explained in the general Mustache support documentation here.

Responses

As a callback return type

To generate an HTTP response rendered from a Mustache template you can simply return a @Mustache-annotated object or a MustacheBodyComponent as the result of your route callback.

The framework will use Mustache to render callback return types that are annotated with the @Mustache annotation or are an instance of a MustacheBodyComponent. E.g.,

@Mustache("foo")
case class FooView(
  name: String)

get("/foo") { request: Request =>
  FooView("abc")
}

The value of the @Mustache annotation is assumed by the c.t.finatra.mustache.writer.MustacheMessageBodyWriter to be the template filename without the suffix (which the framework always assumes to be .mustache).

Thus in the example above, this attempts to locate the foo.mustache template and uses the fields of the FooView to populate the template then returns the result as the body of an 200 - OK response.

Explicitly created response body

Or you can manually create a response via the c.t.finatra.http.response.ResponseBuilder which explicitly references a template, e.g.,

import com.twitter.finatra.http.marshalling.response._

get("/foo") { request: Request =>
  ...
  response.notFound.view(
    template = "notFound.mustache",
    obj = NotFound("abc"))
}

Note

The #view methods are implicits added to the c.t.finatra.http.response.EnrichedResponse by importing the implicit RichEnrichedResponse into scope with import com.twitter.finatra.http.marshalling.response._.

As part of a response body

Or you can programmatically render a template into a string using the c.t.finatra.mustache.marshalling.MustacheService#createString method. This is useful for embedding the resultant content inside a field in a response.

import com.twitter.finatra.mustache.marshalling.MustacheService

case class TestUserView(
  age: Int,
  name: String,
  friends: Seq[String])

case class TestCaseClassWithHtml(
  address: String,
  phone: String,
  renderedHtml: String)

get("/testClassWithHtml") { r: Request =>
  val testUser = TestUserView(
    28,
    "Bob Smith",
    Seq("user1", "user2"))

  TestCaseClassWithHtml(
    address = "123 Main St. Anywhere, CA US 90210",
    phone = "+12221234567",
    renderedHtml = xml.Utility.escape(mustacheService.createString("testHtml.mustache", testUser)))
}

The MustacheService is part of the framework’s generic Mustache support. For more information see the Finatra Mustache section.

Template Resolving

To better understand how Mustache templates are resolved via the @Mustache annotation or from a c.t.finatra.http.marshalling.MessageBodyComponent, please see MustacheTemplateLookup and the corresponding MustacheTemplateLookupTest.

For more information on referencing files in Finatra, see the Working with Files section.