I want to print data in xml format when department is "hr"but data in json format when department is "tech" .
Can we use spray-json Support https://doc.akka.io/docs/akka-http/current/common/json-support.html and XML support https://doc.akka.io/docs/akka-http/current/common/xml-support.html together
private[rest] def route =
(pathPrefix("employee") & get) {
path(Segment) { id =>
parameters('department ? "") { (flag) =>
extractUri { uri =>
complete {
flag match {
case "hr": => {
HttpEntity(MediaTypes.`application/xml`.withCharset(HttpCharsets.`UTF-8`),"hr department")
}
case "tech" =>{
HttpEntity(ContentType(MediaTypes.`application/json`), mapper.writeValueAsString("tech department"))
}
}
}
}
}
}
}
Solution I tried I tried the below by using by using JsonProtocols and ScalaXmlSupport I get the compile error expected ToResponseMarshallable but found Department
case class department(name:String)
private[rest] def route =
(pathPrefix("employee") & get) {
path(Segment) { id =>
parameters('department ? "") { (flag) =>
extractUri { uri =>
complete {
flag match {
case "hr": => {
complete(department(name =flag))
}
case "tech" =>{
complete(department(name =flag))
}
}
}
}
}
}
}
Integration with other JSON libraries are supported by the community. See the list of current community extensions for Akka HTTP. The SprayJsonSupport trait provides a FromEntityUnmarshaller [T] and ToEntityMarshaller [T] for every type T that an implicit spray.json.RootJsonReader and/or spray.json.RootJsonWriter (respectively) is available for.
The support trait is called (unsurprisingly) JacksonSupport, so the code will look like this: Akka HTTP is a magical library for spinning up HTTP services very quickly. In this article, you learned how to use not 1, but 3 different libraries for serializing and deserializing JSON auto-magically with directives.
akka-http-json provides JSON (un)marshalling support for Akka HTTP via the following JSON libraries: The artifacts are published to Maven Central. libraryDependencies ++= Seq ( "de.heikoseeberger" %% "akka-http-circe" % AkkaHttpJsonVersion , ... )
Integration with spray-json is provided out of the box through the akka-http-spray-json module. Integration with other JSON libraries are supported by the community. See the list of current community extensions for Akka HTTP.
I think there are several issues you have to overcome to achieve what you want:
You want to customize response type basing on the request parameters. It means standard implicit
-based marshaling will not work for you, you'll have to do some explicit steps
You want to marshal into an XML-string some business objects. Unfortunately, ScalaXmlSupport
that you referenced does not support this, it can marshal only an XML-tree into a response. So you'll need some library that can do XML serialization. One option would be to use jackson-dataformat-xml with jackson-module-scala. It also means you'll have to write your own custom Marshaller
. Luckily it is not that hard.
So here goes some simple code that might work for you:
import akka.http.scaladsl.marshalling.{ToResponseMarshallable, Marshaller}
// json marshalling
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json._
import spray.json.DefaultJsonProtocol._
implicit val departmentFormat = DefaultJsonProtocol.jsonFormat1(department)
val departmentJsonMarshaller = SprayJsonSupport.sprayJsonMarshaller[department]
// xml marshalling, need to write a custom Marshaller
// there are several MediaTypes for XML such as `application/xml` and `text/xml`, you'll have to choose the one you need.
val departmentXmlMarshaller = Marshaller.StringMarshaller.wrap(MediaTypes.`application/xml`)((d: department) => {
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
val mapper = new XmlMapper()
mapper.registerModule(DefaultScalaModule)
mapper.writeValueAsString(d)
})
private val route =
(pathPrefix("employee") & get) {
path(Segment) { id =>
parameters('department ? "") { (flag) =>
extractUri { uri => {
flag match {
case "hr" => {
// explicitly use the XML marshaller
complete(ToResponseMarshallable(department(name = flag))(departmentXmlMarshaller))
}
case "tech" => {
// explicitly use the JSON marshaller
complete(ToResponseMarshallable(department(name = flag))(departmentJsonMarshaller))
}
}
}
}
}
}
}
Note that for Jackson XML serializer to work correctly the department
class should be a top level class or you'll get a cryptic error about bad root name.
Akka Http already has built in content type negotiation. Ideally you should just use that by having a marshaller that knows how to turn your department into either xml or json and having the client set the Accept
header.
However it sounds like maybe you can't get your client to do that, so here's what you can do, assuming you have already made a ToEntityMarshaller[department]
for both xml and json using ScalaXmlSupport
and SprayJsonSupport
.
val toXmlEntityMarshaller: ToEntityMarshaller[department] = ???
val toJsonEntityMarshaller: ToEntityMarshaller[department] = ???
implicit val departmentMarshaller = Marshaller.oneOf(toJsonEntityMarshaller, toXmlEntityMarshaller)
def route =
parameters("department") { departmentName =>
// capture the Accept header in case the client did request one
optionalHeaderValueByType[Accept] { maybeAcceptHeader =>
mapRequest ( _
.removeHeader(Accept.name)
// set the Accept header based on the department
.addHeader(maybeAcceptHeader.getOrElse(
Accept(departmentName match {
case "hr" ⇒ MediaTypes.`application/xml`
case "tech" ⇒ MediaTypes.`application/json`
})
))
) (
// none of our logic code is concerned with the response type
complete(department(departmentName))
)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With