How to unmarshal POST params and JSON body in a single route?
Asked Answered
A

1

7

I have this route:

val routes =
    pathPrefix("api") {
      path("ElevationService" / DoubleNumber / DoubleNumber) { (long, lat) =>
        post {
          requestContext =>
            println(long, lat)
        }
      }
    }

This works nicely, I can call my ElevationService as:

http://localhost:8080/api/ElevationService/39/80

The problem is, I also want to parse the body sent to me in the request as JSON. It looks as follows:

{
  "first": "test",
  "second": 0.50
}

I've managed to get it to work in a separate route following the documentation on the entity directive:

path("test") {
   import scrive.actors.ScriveJsonProtocol
   import spray.httpx.SprayJsonSupport._
   post {
      entity(as[ScriveRequest]) { scrive =>
        complete(scrive)
      }
   }
}

But I don't know how to merge these two routes into one. Since they're wrapped in functions, I can't call the params long, lat from within the entity function, they doesn't exist in that scope I suppose. The same goes or the other way around.

I want to be able to access both my params and my POST body, and then call a service passing all the data:

val elevationService = actorRefFactory.actorOf(Props(new ElevationService(requestContext)))
elevationService ! ElevationService.Process(long, lat, bodyParams)
Athamas answered 30/12, 2014 at 15:1 Comment(0)
R
7

You can just nest the directives:

 path("ElevationService" / DoubleNumber / DoubleNumber) { (long, lat) =>
   post {
     entity(as[ScriveRequest]) { scrive =>
       onSuccess( elevationService ? ElevationService.Process(long, lat, bodyParams) ) {
         actorReply =>
           complete(actorReply)
       }
     }
 }

You can also use & to combine two directives more directly:

(path("ElevationService" / DoubleNumber / DoubleNumber) & entity(as[ScriveRequest])) {
  (long, lat, scriveRequest) => ...
Recapitulate answered 30/12, 2014 at 15:6 Comment(2)
Thank you, I will give it a try, but I get "Missing parameter type: actorReply", obviously since it's not defined anywhere. Is this "actorReply" some kind of callback for the Actor, or what is it for. I'm sorry if I ask dumb question, I'm just getting started with spray and this dsl routing is so confusing.Athamas
actorReply is what I was using as the name for the response from the actor. I forgot that akka is untyped, so it would probably need a cast. If you don't need to wait for a response from the actor then you don't need the ? or the onSuccess, you can just use ! to send a fire-and-forget message to the actor and leave it there.Recapitulate

© 2022 - 2024 — McMap. All rights reserved.