Marshalling/Unmarshalling in Akka HTTP

Reading Time: 4 minutes

In this blog we are going to discuss about Marshalling/Unmarshalling in Akka HTTP. Before discussing it lets have a look at Akka HTTP.

Akka HTTP  offers a toolkit for providing and consuming HTTP-based services. The Akka HTTP modules implement a full server- and client-side HTTP. It provides client-side and server-side API to send HTTP requests and HTTP responses.To transfer data over the network, we need to convert the data into a “wire-format” because the network is not aware of our application layer’s data format. For HTTP, the wire format is HTTP requests and responses. For the entity (body) of HTTP requests and responses, we can choose the wire format as specified in the Content-Type HTTP header. Some Content-Type examples are:

  • Content-Type: application/json
  • Content-Type: text/plain; charset=utf-8
  • Content-Type: application/x-www-form-urlencoded
  • Content-Type: application/octet-stream

Marshalling is the process of converting a higher-level (object) structure into some kind of lower-level representation, often a wire format. It means the conversion of an object of type T into a lower-level target type. e.g. a MessageEntity (which forms the “entity-body” of an HTTP request or response) or a full HttpRequest or HttpResponse.

Unmarshalling is the process of converting some kind of a lower-level representation, often a “wire format”, into a higher-level (object) structure. It means the conversion of a lower-level source object e.g. a MessageEntity (which forms the “entity-body” of an HTTP request or response) or a full HttpRequest and HttpResponse into an instance of type T.
In this blog, we will discuss the marshalling/unmarshalling of custom types using spray-json, play-json, jackson, Json4s. Instead of passing a plain string through HttpRequest and Http Response, you can pass a Scala case class. Usually, JSON is the format used during communication. 

Using spray-json library

To make the JSON to/from Scala case class conversion happen, fortunately, Akka HTTP is designed so that we don’t need to understand what’s happening inside. We just need to know what to import and what kind of implicit to define so Add following library dependency into build.sbt

libraryDependencies += "com.typesafe.akka" %%"akka-http-spray-json" % "10.1.9"

After updating build.sbt we need some imports and introduce a case class which you want to return through HttpResponse. For Marshalling, add implicit which will be placed in the companion object of case class. jsonFormat2 is a convenient method which takes the apply method of a two-value case class and returns RootJsonFormat.

import spray.json.RootJsonFormat
import spray.json.DefaultJsonProtocol._
Import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport. _


case class User(name: String, age: Int)

object User{
 implicit val userJsonFormat: RootJsonFormat[User] = jsonFormat2(User.apply)
}

While sending response just pass User instance to the complete method and User can now be converted to JSON.

get {
 complete(User(name = "abc", age = 21))
}

For unmarshalling,we use the entity and as directive(s) on the server side to convert JSON requests into a Scala User case class instance.

post{
 entity(as[User]){user =>
   complete(StatusCodes.Created,user)
 }

Using Jackson library

If you want to use jackson to marshalling then it needs following library dependency

libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.9"

 To understand the use of jackson library we will consider the same example as above. After adding above library dependencies in build.sbt we need some imports. consider there is a case class User and add code for marshalling in the companion object of case class as follows.

import com.fasterxml.jackson.databind.{ ObjectMapper}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

case class User(name: String, age: Int)

object User{

 val mapper = new ObjectMapper() with ScalaObjectMapper
 mapper.registerModule(DefaultScalaModule)

 def toJson(value: Any)= {
   mapper.writeValueAsString(value)
 }
}

In above example writeValueAsString is the method which takes custom type and will convert it to Json object. You just need to call toJson method while sending HttpResponse.

get{
    complete(User.toJson(User("abc",21)))
}

Using Play Json library

The play.api.libs.json package contains data structures for representing JSON data and utilities for converting between these data structures and other data representations. Play supports HTTP requests and responses with a content type of JSON by using the HTTP API in combination with the JSON library.

For (un)marshalling use following library dependencies

libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.7"

libraryDependencies +=   "de.heikoseeberger" %% "akka-http-play-json" % "1.20.0"

After updating build.sbt add following code in scala file

import de.heikoseeberger.akkahttpplayjson.PlayJsonSupport
import play.api.libs.json.{Json, OWrites, Reads}

case class Person(name:String,age:Int)

object Person{
 implicit val toJson: OWrites[Person] = Json.writes[Person]
 implicit val fromJson: Reads[Person] = Json.reads[Person]
}

Reads and OWrites converters which are used to convert between Jsvalue structures.OWrites used to convert from scala object to json and Reads used to convert json into scala object.click here to know how both exactly works.After adding above code you can send scala object in HTTP entity.

Using Json4s

Json4s library gives one of the best results for (un)marshalling in scala 

You just need to import org.json4s._ so that you can have Strings implicitly converted to JStrings, ints to JInts and also you need to add following library dependency.

libraryDependencies += "org.json4s" %% "json4s-native" % "3.2.11"

Add following imports and code into your scala file. To keep things simpler, I have a Student case class which contains two fields roll number and name of the student.

import org.json4s._
import org.json4s.native.Serialization.{write => jWrite}

case class Student(rollNum: Int, name: String)

object Student{

 implicit val formats: Formats = DefaultFormats
 def write[T <: AnyRef](value: T): String = jWrite(value)
}

And companion object of Student has necessary implicit. While sending http response you just need to call the write method. click here to do deep study of how Json4s implicitly works.

There are a lot of JSON conversion libraries including argonaut,circe,uPickle and more for marshalling/unmarshalling. So instead of forcing us to use its default implementation Akka HTTP lets us choose our favorite JSON conversion library and plug it in.

Feel free to download and run code of marshalling/unmarshalling in akka http.

Refferences –

1.https://doc.akka.io/docs/akka-http/current/index.html

2. https://nosqlnocry.wordpress.com/2015/04/16/working-with-json-in-sc ala-using-the-json4s-library-part-one/

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading