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
libraryDependencies += "com.typesafe.akka" %% "akka-http-spray-json" % "10.1.0"
Gradle
dependencies {
  compile group: 'com.typesafe.akka', name: 'akka-http-spray-json_2.12', version: '10.1.0'
}
Maven
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-http-spray-json_2.12</artifactId>
  <version>10.1.0</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
libraryDependencies += "com.typesafe.akka" %% "akka-http-jackson" % "10.1.0"
Gradle
dependencies {
  compile group: 'com.typesafe.akka', name: 'akka-http-jackson_2.12', version: '10.1.0'
}
Maven
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-http-jackson_2.12</artifactId>
  <version>10.1.0</version>
</dependency>

Use akka.http.javadsl.marshallers.jackson.Jackson.unmarshaller(T.class) to create an Unmarshaller<HttpEntity,T>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 refer 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>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.

Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.