Skip to content
This repository has been archived by the owner on Apr 24, 2024. It is now read-only.

Marshalling and Unmarshalling

Johannes Rudolph edited this page Aug 14, 2013 · 11 revisions

. . . Deprecation Note

This documentation is for release 0.9.0 (from 03/2012), which is built against Scala 2.9.1 and Akka 1.3.1 (see Requirements for more information). Most likely, this is not the place you want to look for information. Please turn to the main spray site at http://spray.io for more information about other available versions.

. . .

HTTP requests and responses can have an "entity body", which can be text or binary content. However, when consuming requests and producing responses in your application you normally want to work with your domain objects rather than low level representations in XML, JSON or other serialization formats.

spray supports decoupling your application logic from these serialization concerns by separating out marshalling (converting domain objects to a serialized format) and unmarshalling (creating domain objects from a serialized format) in the way of type classes.

Suppose your application provides actions upon Person resources, which are represented in your code like this:

case class Person(name: string, firstname: String, age: int)

A part of your spray service might be defined like this:

path("person" / IntNumber) { id =>
  get { ctx =>
    val person: Person = ... // load Person from the DB using the id
    ctx.complete(person) // uses the in-scope Marshaller to convert the
                         // Person into a format accepted by the client
  } ~
  put {
    content(as[Person]) { person =>
      ... // operate directly on the Person object,
          // e.g. write it to the database                          
    }
  }
}

Marshalling

When you use the RequestContext complete method with an argument of a custom type the Scala compiler will look for an in-scope implicit Marshaller for your type to do the job of converting your custom object to a representation accepted by the client. spray comes with the following marshallers already defined (as implicit objects in the DefaultMarshallers trait):

  • Array[Byte] to application/octet-stream
  • Array[Char] to media type text/plain
  • String to media type text/plain
  • NodeSeq to text/xml, text/html or application/xhtml+xml
  • FormData to application/x-www-form-urlencoded
  • MultipartFormData to multipart/form-data
  • [MultipartContent] to multipart/mixed
  • Option[T] to a the respective type for T or a 404 Not Found response if undefined
  • Either[A, B] to the respective response of either A or B
  • Future[T] to the respective response of T
  • Stream[T] to the respective streaming response (see Streaming)
  • Throwable to the respective error response
  • twirl.api.{Xml, Txt, Html} to the respective mediatype (with TwirlSupport
  • Any type T to application/json (with [SprayJsonSupport] or LiftJsonSupport)

Creating your own marshallers for custom types is also not hard at all. For guidance take a look at the implementation of the built-in marshallers in DefaultMarshallers trait.

Unmarshalling

The opposite of marshalling is unmarshalling, i.e. the creation of custom objects from XML, JSON and the like. This job is done by Unmarshaller instances, which just like Marshaller instances, are really easy to write for your custom types and need to be available implicitly. spray comes with the following unmarshallers already defined (as implicit vals in the DefaultUnmarshallers trait):

  • Media type application/octet-stream to Array[Byte]
  • Media type text/plain to Array[Char]
  • Media type text/plain to String
  • text/xml, text/html or application/xhtml+xml to NodeSeq
  • application/x-www-form-urlencoded to FormData
  • multipart/form-data to MultipartFormData
  • multipart/mixed to [MultipartContent]
  • application/json to any type T (with [SprayJsonSupport] or LiftJsonSupport)