JSON Support

Akka HTTP’s marshalling and unmarshalling infrastructure makes it rather easy to seamlessly convert application-domain objects from and to JSON. Integration with spray-jsonJackson is provided out of the box through the akka-http-spray-jsonakka-http-jackson module. Integration with other JSON libraries are supported by the community. See the list of current community extensions for Akka HTTP.

spray-json Support

The SprayJsonSupport trait provides a FromEntityUnmarshaller[T] and ToEntityMarshaller[T] for every type T that an implicit spray.json.RootJsonReader and/or spray.json.RootJsonWriter (respectively) is available for.

To enable automatic support for (un)marshalling from and to JSON with spray-json, add a library dependency onto:

sbt
"com.typesafe.akka" %% "akka-http-spray-json" % "10.0.10" 
Gradle
compile group: 'com.typesafe.akka', name: 'akka-http-spray-json_2.12', version: '10.0.10'
Maven
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-http-spray-json_2.12</artifactId>
  <version>10.0.10</version>
</dependency>

Next, provide a RootJsonFormat[T] for your type and bring it into scope. Check out the spray-json documentation for more info on how to do this.

Finally, import the FromEntityUnmarshaller[T] and ToEntityMarshaller[T] implicits directly from SprayJsonSupport as shown in the example below or mix the akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport trait into your JSON support module.

Once you have done this (un)marshalling between JSON and your type T should work nicely and transparently.

import akka.http.scaladsl.server.Directives
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json._

// domain model
final case class Item(name: String, id: Long)
final case class Order(items: List[Item])

// collect your json format instances into a support trait:
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
  implicit val itemFormat = jsonFormat2(Item)
  implicit val orderFormat = jsonFormat1(Order) // contains List[Item]
}

// use it wherever json (un)marshalling is needed
class MyJsonService extends Directives with JsonSupport {

  // format: OFF
  val route =
    get {
      pathSingleSlash {
        complete(Item("thing", 42)) // will render as JSON
      }
    } ~
    post {
      entity(as[Order]) { order => // will unmarshal JSON to Order
        val itemsCount = order.items.size
        val itemNames = order.items.map(_.name).mkString(", ")
        complete(s"Ordered $itemsCount items: $itemNames")
      }
    }
  // format: ON
}

Pretty printing

By default, spray-json marshals your types to compact printed JSON by implicit conversion using CompactPrinter, as defined in:

implicit def sprayJsonMarshallerConverter[T](writer: RootJsonWriter[T])(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[T] =
  sprayJsonMarshaller[T](writer, printer)

Alternatively to marshal your types to pretty printed JSON, bring a PrettyPrinter in scope to perform implicit conversion.

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json._

// domain model
final case class PrettyPrintedItem(name: String, id: Long)

object PrettyJsonFormatSupport {
  import DefaultJsonProtocol._
  implicit val printer = PrettyPrinter
  implicit val prettyPrintedItemFormat = jsonFormat2(PrettyPrintedItem)
}

// use it wherever json (un)marshalling is needed
class MyJsonService extends Directives {
  import PrettyJsonFormatSupport._

  // format: OFF
  val route =
    get {
      pathSingleSlash {
        complete {
          PrettyPrintedItem("akka", 42) // will render as JSON
        }
      }
    }
  // format: ON
}

val service = new MyJsonService

// verify the pretty printed JSON
Get("/") ~> service.route ~> check {
  responseAs[String] shouldEqual
    """{""" + "\n" +
    """  "name": "akka",""" + "\n" +
    """  "id": 42""" + "\n" +
    """}"""
}

To learn more about how spray-json works please refer to its documentation.

Jackson Support

To make use of the support module for (un)marshalling from and to JSON with Jackson, add a library dependency onto:

sbt
"com.typesafe.akka" %% "akka-http-jackson" % "10.0.10" 
Gradle
compile group: 'com.typesafe.akka', name: 'akka-http-jackson_2.12', version: '10.0.10'
Maven
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-http-jackson_2.12</artifactId>
  <version>10.0.10</version>
</dependency>

Use akka.http.javadsl.marshallers.jackson.Jackson.unmarshaller(T.class) to create an Unmarshaller<HttpEntity,T> which expects the request body (HttpEntity) to be of type application/json and converts it to T using Jackson.

import akka.http.javadsl.marshallers.jackson.Jackson;
import akka.http.javadsl.model.StatusCodes;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import static akka.http.javadsl.server.Directives.*;
import static akka.http.javadsl.unmarshalling.StringUnmarshallers.INTEGER;

public static Route appRoute(final Map<Integer, Pet> pets) {
  PetStoreController controller = new PetStoreController(pets);

  // Defined as Function in order to refere to [pets], but this could also be an ordinary method.
  Function<Integer, Route> existingPet = petId -> {
      Pet pet = pets.get(petId);
      return (pet == null) ? reject() : complete(StatusCodes.OK, pet, Jackson.<Pet>marshaller());
  };

  // The directives here are statically imported, but you can also inherit from AllDirectives.
  return
    route(
      path("", () ->
        getFromResource("web/index.html")
      ),
      pathPrefix("pet", () -> 
        path(INTEGER, petId -> route(
          // demonstrates different ways of handling requests:

          // 1. using a Function
          get(() -> existingPet.apply(petId)),

          // 2. using a method
          put(() -> 
            entity(Jackson.unmarshaller(Pet.class), thePet -> 
              putPetHandler(pets, thePet)
            )
          ),
          // 2.1. using a method, and internally handling a Future value
          path("alternate", () ->
            put(() -> 
              entity(Jackson.unmarshaller(Pet.class), thePet -> 
                putPetHandler(pets, thePet)
              )
            )              
          ),

          // 3. calling a method of a controller instance
          delete(() -> controller.deletePet(petId))
        ))
      )
    );
}

Use akka.http.javadsl.marshallers.jackson.Jackson.marshaller(T.class) to create a Marshaller<T,RequestEntity> which can be used with RequestContext.complete or RouteDirectives.complete to convert a POJO to an HttpResponse.

import akka.http.javadsl.marshallers.jackson.Jackson;
import akka.http.javadsl.model.StatusCodes;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import static akka.http.javadsl.server.Directives.*;
import static akka.http.javadsl.unmarshalling.StringUnmarshallers.INTEGER;

private static Route putPetHandler(Map<Integer, Pet> pets, Pet thePet) {
    pets.put(thePet.getId(), thePet);
    return complete(StatusCodes.OK, thePet, Jackson.<Pet>marshaller());
}

private static Route alternativeFuturePutPetHandler(Map<Integer, Pet> pets, Pet thePet) {
    pets.put(thePet.getId(), thePet);
  CompletableFuture<Pet> futurePet = CompletableFuture.supplyAsync(() -> thePet);
    return completeOKWithFuture(futurePet, Jackson.<Pet>marshaller());
}

Refer to this file in the sources for the complete example.

The source code for this page can be found here.