Question

I am trying to replace a Jetty-based back-end by a pure spray-can + spray-routing one.

The front-end posts JSON content using the text/json media type. I've never had any problems with this with Jetty. I have just realized that it is not a standard type thanks to spray, which only accepts the correct and standard application/json media type.

Is there any easy way to map one to the other at the server side? I would really like to avoid having to introduce an ad-hoc release of the client side of the application to deal with this. Of course, I will make the change for the next scheduled release, but for now I need a "quick and dirty" fix.

I have tried changing the header from text/json to application/json using the following function:

def correctJsonHeaders(req:spray.http.HttpRequest) = {
  val tweakedHeaders = req.headers.map{ hdr =>
    if(hdr.name == "Content-Type" && hdr.value == "text/json")
      `Content-Type`(`application/json`)
    else
      hdr
  }
  req.copy(headers = tweakedHeaders)
}

in my route directive, like so:

path("route"){
  mapRequest(correctJsonHeaders){
    post{
      respondWithMediaType(`application/json`) {
        handleWith{ x:TypeThatUnmarshallsFromJson =>
          bizLogicReturningAJsonString(x)
        }
      }
    }
  }
}

Although the header is correctly changed, I still get a 415 error (which goes away if I change the media type to application/json at the client)

Was it helpful?

Solution

After reading the documentation on the spray-http Content-Type Header, I changed my function to:

def correctJsonHeaders(req:spray.http.HttpRequest) = {
  if(req.headers.exists(hdr => hdr.name == "Content-Type" && hdr.value == "text/json")){
    val tweakedEntity = spray.http.HttpEntity(`application/json`, req.entity.data)
    req.copy(entity = tweakedEntity)
  }
  else req
}

which seems to work. The trick was to change the HttpEntity, instead of the header.

OTHER TIPS

The lack of support for custom Accept and Content-Type headers is caused by the implementation of the JSON marshaller you use. Have a look at the source code of these traits to see where this happens:

  • spray.httpx.LiftJsonSupport
  • spray.httpx.Json4sJacksonSupport
  • spray.httpx.PlayJsonSupport
  • spray.httpx....

Simply solve this by implementing your own PlayJsonSupport trait and add your custom MediaType and ContentType to the two delegate functions. We needed this as well because we put our vendor version in our accept headers to support versioning on our REST services.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top