2014-01-23 6 views
2

Использование Spray Routing, я хотел бы иметь одну директиву, которая объединяет параметры строки запроса с сущностью JSON, причем оба являются необязательными. Я хотел бы, чтобы это произошло до того, как произойдет любое сортирование.Объединить параметры строки запроса с JSON Entity в Spray 1.2.0 Маршрутизация

Что-то вроде этого:

val myRoute = mergedParametersAndEntity(as[DomainSpecificClass]) { myobj => 
    // ... code code code ... 
    complete(OK, myobj.someMethod) 
} 

В основном то, что я надеялся было следующее поведение:

Когда кто-то делает запрос как:

POST /v1/resource?a=helloQS&b=helloQS 
Content-Type: application/json 

{"a":"helloFromJson","c":"helloFromJson"} 

Тогда объект выше (myobj) могут содержать ключи:

a -> helloFromJson 
b -> helloQS 
c -> helloFromJson 

Иными словами, элементы, указанные в теле запроса, будут переопределять элементы в строке запроса. Я знаю, что это должно быть возможно каким-то образом, но я просто не могу понять, как это сделать. Может ли кто-нибудь помочь?

Спасибо!

ответ

2

Мое предложение: не принимайте такой подход. Он чувствует себя грязным. Вернитесь к чертежной доске, если сможете.

С учетом этого вы не сможете вставлять слияние, как вы хотите, с существующей поддержкой JSON в Spray. Вам нужно сшить его вместе. Что-то, как это должно, по крайней мере направить вас в правильном направлении (при условии, что будет направление вы должны идти):

import org.json4s.JsonAST._ 
import org.json4s.JsonDSL._ 
def mergedParametersAndEntity[T](implicit m:Manifest[T]): Directive1[T] = { 
    entity(as[JObject]).flatMap { jObject => 
    parameterMap flatMap { params => 
     val left = JObject(params.mapValues { v => JString(v) }.toSeq : _*) 
     provide(left.merge(jObject).extract[T]) 
    } 
    } 
} 
0

Если кто-то до сих пор интересно, как это сделать здесь небольшую директиву Spray, что позволяет значения копирования Param в JSON, прежде чем раскручивать его. Он использует объективы JSON (https://github.com/jrudolph/json-lenses), чтобы модифицировать тело запроса до его отмены.

def updateJson(update: Update): Directive0 = { 
    mapRequest((request: HttpRequest) => { 
    request.entity match { 
     case Empty => request 
     case NonEmpty(contentType, data) => 
     try { 
      request.copy(entity = HttpEntity(`application/json`, JsonParser(data.asString).update(update).toString)) 
     } 
     catch { 
      case e: ParsingException => request 
     } 
    } 
    }) 
} 

И вот как вы его используете. Допустим, вы хотите обновить ресурс с запросом PUT и передать идентификатор из URL в unmarshaller (очень распространенный сценарий кстати):

// Model 
case class Thing(id: Long, title: String, description: String, createdAt: DateTime) 

// Actor message for the update operation 
case class UpdateThing(id: Long, title: String) 

// Spray routing 
def thingsRoute = 
    path("things"/Segment) { id => 
    put { 
     updateJson(field("id") ! set[Long](id)) { 
     entity(as[UpdateThing]) { updateThing => 
      complete { 
      // updateThing now has the ID set 
      (someActor ? updateThing).mapTo[Thing] 
      } 
     } 
     } 
    } 
    } 

Вы также можете комбинировать его с parameters директивы установить произвольные GET Params ,