completeWith
Description
Uses the marshaller for a given type to produce a completion function that is passed to its inner route. You can use it to decouple marshaller resolution from request completion.
The completeWith
directive works in conjunction with the instanceOf
directive to convert higher-level (object) structure into some lower-level serialized “wire format”. The marshalling documentation explains this process in detail. This directive simplifies exposing types to clients via a route while providing some form of access to the current context.
completeWith
is similar to handleWith
. The main difference is with completeWith
you must eventually call the completion function generated by completeWith
. handleWith
will automatically call complete
when the handleWith
function returns.
Examples
The following example uses spray-json
Json Support via Jackson to marshall a simple Person
class to a json response. It utilizes SprayJsonSupport
via the PersonJsonSupport
object as the in-scope unmarshaller.
- Scala
-
source
import spray.json.{ DefaultJsonProtocol, RootJsonFormat } object PersonJsonSupport extends DefaultJsonProtocol with SprayJsonSupport { implicit val personFormat: RootJsonFormat[Person] = jsonFormat2(Person.apply) } case class Person(name: String, favoriteNumber: Int)
- Java
-
source
public static class Person { private final String name; private final int favoriteNumber; // default constructor required for Jackson public Person() { this.name = ""; this.favoriteNumber = 0; } public Person(String name, int favoriteNumber) { this.name = name; this.favoriteNumber = favoriteNumber; } public String getName() { return name; } public int getFavoriteNumber() { return favoriteNumber; } }
The findPerson
takes an argument of type Person => Unit
Consumer<Consumer<Person>>
which is generated by the completeWith
call. We can handle any logic we want in findPerson
and call our completion function to complete the request.
- Scala
-
source
import PersonJsonSupport._ val findPerson = (f: Person => Unit) => { // ... some processing logic... // complete the request f(Person("Jane", 42)) } val route = get { completeWith(instanceOf[Person]) { completionFunction => findPerson(completionFunction) } } // tests: Get("/") ~> route ~> check { mediaType shouldEqual `application/json` responseAs[String] should include(""""name":"Jane"""") responseAs[String] should include(""""favoriteNumber":42""") }
- Java
-
source
import static org.apache.pekko.http.javadsl.server.Directives.completeWith; final Marshaller<Person, HttpResponse> marshaller = Marshaller.entityToOKResponse(Jackson.<Person>marshaller()); // Please note that you can also pass completionFunction to another thread and use it there to // complete the request. // For example: // final Consumer<Consumer<Person>> findPerson = completionFunction -> { // CompletableFuture.runAsync(() -> // /* ... some processing logic... */ // completionFunction.accept(new Person("Jane", 42))); // }; final Consumer<Consumer<Person>> findPerson = completionFunction -> { // ... some processing logic... // complete the request completionFunction.accept(new Person("Jane", 42)); }; final Route route = completeWith(marshaller, findPerson); // tests: final TestRouteResult routeResult = testRoute(route).run(HttpRequest.GET("/")); routeResult.assertMediaType(MediaTypes.APPLICATION_JSON); routeResult.assertEntity("{\"favoriteNumber\":42,\"name\":\"Jane\"}");