Message Body Components

Message body components specify how to parse an incoming Finagle HTTP request into a model or domain object (“message body reader”) and how to transform a given type T into a Finagle HTTP response (“message body writer”).

Note

Classes in internal packages (i.e., com.twitter.finatra.http.internal) are not expected to be used directly and no guarantee is given as to the stability of their interfaces. Please do not use these classes directly.

Message Body Readers

Message body readers can be registered through the HttpRouter much like adding a Controller or a Filter.

import DoEverythingModule
import ExampleController
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.finatra.http.{Controller, HttpServer}

object ExampleServerMain extends ExampleServer

class ExampleServer extends HttpServer {

  override val modules = Seq(
    DoEverythingModule)

  override def configureHttp(router: HttpRouter): Unit = {
    router
      .add[ExampleController]
      .register[MyModelObjectMessageBodyReader]
  }
}

Message body readers are used to convert an incoming Finagle HTTP request into a type T which is specified as the input type for a route callback.

E.g., a controller with a route specified:

import com.twitter.finatra.http.Controller

class ExampleController extends Controller {

  get("/") { model: MyModelObject =>
    ...
  }

will trigger the framework to search for a registered message body reader that can convert the incoming Finagle HTTP request to MyModelObject. If a message body reader for the MyModelObject type cannot be found the DefaultMessageBodyReader implementation configured in the MessageBodyManager will be used.

DefaultMessageBodyReader

The framework provides a default message body reader implementation: c.t.finatra.http.internal.marshalling.DefaultMessageBodyReaderImpl which is invoked when a more specific message body reader cannot be found to convert an incoming Finagle HTTP request.

The DefaultMessageBodyReaderImpl parses an incoming Finagle HTTP request body as JSON, marshalling it into the given callback input type using the HttpServer configured FinatraObjectMapper and is the basis of the JSON integration with routing.

This default behavior is overridable. See the c.t.finatra.http.modules.MessageBodyModule section for more information on how to provide a different DefaultMessageBodyReader implementation.

Message Body Writers

Like message body readers, writers can be registered through the HttpRouter – again like adding a Controller or a Filter.

import DoEverythingModule
import ExampleController
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.finatra.http.{Controller, HttpServer}

object ExampleServerMain extends ExampleServer

class ExampleServer extends HttpServer {

 override val modules = Seq(
   DoEverythingModule)

 override def configureHttp(router: HttpRouter): Unit = {
   router
     .add[ExampleController]
     .register[MyModelObjectMessageBodyReader]
     .register[MyModelObjectMessageBodyWriter]
 }
}

Message body writers are used to specify conversion from a type T to a Finagle HTTP response. This can be for the purpose of informing the framework how to render the return type of a route callback or how to render a type passed as a body to a function in the c.t.finatra.http.response.ResponseBuilder.

E.g., a controller with a route specified:

import com.twitter.finagle.http.Request
import com.twitter.finatra.http.Controller

class ExampleController extends Controller {

  get("/") { request: Request =>
    ...
    MyRenderableObjectType(
      id = "1",
      name = "John Doe",
      description = "A renderable return")
  }

will trigger the framework to search for a registered message body writer that can convert the MyRenderableObjectType type into a Finagle HTTP response. If a message body writer for the MyRenderableObjectType type cannot be found the DefaultMessageBodyWriter implementation configured in the MessageBodyManager will be used.

DefaultMessageBodyWriter

The framework provides a default message body writer implementation: c.t.finatra.http.internal.marshalling.DefaultMessageBodyWriterImpl which is invoked when a more specific message body writer cannot be found to convert given type T into a Finagle HTTP response.

The DefaultMessageBodyWriterImpl converts any non-primitive type to a application/json content-type response and a JSON representation of the type using the HttpServer configured FinatraObjectMapper to convert the type to JSON.

For primitive and wrapper types, the default writer implementation will render a plain/text content-type response using the type’s toString value.

This default behavior is overridable. See the c.t.finatra.http.modules.MessageBodyModule section for more information on how to provide a different DefaultMessageBodyWriter implementation.

MessageBodyManager

The MessageBodyManager registers message body components. Generally, you will not need to interact directly with the manager as a DSL for registration of components is provided by the HttpRouter (which uses the MessageBodyManager underneath).

c.t.finatra.http.modules.MessageBodyModule

The DefaultMessageBodyReader, and the DefaultMessageBodyWriter are provided by the framework via the c.t.finatra.http.modules.MessageBodyModule.

To override the framework defaults, create a TwitterModule which provides customized implementations for the default reader and writer.

Set this module by overriding the protected def messageBodyModule in your server.

class ExampleServer extends HttpServer {

  override def messageBodyModule = MyCustomMessageBodyModule

  override def configureHttp(router: HttpRouter): Unit = {
    ...
  }
}

If your module is defined as a class, you would pass an instance of the class, e.g.,

override def messageBodyModule = new MyCustomMessageBodyModule

See Framework Modules for more information.

Mustache Support

Mustache support is provided through a combination of the c.t.finatra.http.modules.MessageBodyModule and a specific Mustache message body writer.

Finatra provides the c.t.finatra.http.internal.marshalling.mustache.MustacheMessageBodyWriter which transforms either a c.t.finatra.http.marshalling.MessageBodyComponent or an object annotated with the @Mustache annotation. The transformation is performed using a referenced Mustache template specified by either the component configuration or as a parameter configured in the @Mustache annotation.

See the MessageBodyManager#addByAnnotation and MessageBodyManager#addByComponentType methods for adding an annotated Mustache view to the MessageBodyManager and adding a MessageBodyComponent by type to the MessageBodyManager which will instantiate an instance of the type via the injector.

For examples of how to use the Finatra Mustache support, please see the Finatra web-dashboard example and the MustacheController used in integration tests.

To better understand how Mustache templates are found, please see MustacheTemplateLookup and the corresponding MustacheTemplateLookupTest.

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