Search code examples
jsonscalaspraycase-classjson4s

json4s object extraction with extra data


I'm using spray with json4s, and I've got the implementation below to handle put requests for updating objects... My problem with it, is that I first extract an instance of SomeObject from the json, but being a RESTful api, I want the ID to be specified in the URL. So then I must somehow create another instance of SomeObject that is indexed with the ID... to do this, I'm using a constructor like SomeObject(id: Long, obj: SomeObject). It works well enough, but the implementation is ugly and it feels inefficient. What can I do so I can somehow stick the ID in there so that I'm only creating one instance of SomeObject?

class ApplicationRouter extends BaseRouter {
  val routes =
    pathPrefix("some-path") {
      path("destination-resource" \ IntNumber) { id =>
        entity(as[JObject]) { rawData =>
          val extractedObject = rawData.camelizeKeys.extract[SomeObject]
          val extractedObjectWithId = SomeObject(id, extractedObject)
          handleRequest(extractedObjectWithId)
        }
      }
    }
}

case class SomeObject(id: Long, data: String, someValue: Double, someDate: DateTime) {
  def this(data: String, someValue: Double, someDate: DateTime) = this(0, data, someValue, someDate)
  def this(id: Long, obj: SomeObject) = this(id, obj.data, obj.someValue, obj.someDate)
}

Solution

  • I figured out a solution to this after digging around through the docs for awhile:

    class ApplicationRouter extends BaseRouter {
      val routes =
        pathPrefix("some-path") {
          path("destination-resource" \ IntNumber) { id =>
            entity(as[JObject]) { rawData =>
              val extractedObject = rawData.camelizeKeys.merge { 
                  ("id", id)
              }.extract[SomeObject]
              handleRequest(extractedObject)
            }
          }
        }
    }