Parse request body with custom content-type to json in Play Framework - scala

I'm using play to proxy my API calls from the ui. For example POST:
def post(url: String) = Action { implicit request =>
Async {
WS.url(proxyUrl + request.uri)
.withQueryString(request.queryString.mapValues(_.head).toSeq: _*)
.withHeaders(request.headers.toMap.mapValues(_.head).toSeq: _*)
.post(request.body.asJson).map(response => Ok(response.body))
}
}
but this can only handle "application/json" and "text/json" content types. But now I want to make requests with custom content type: "application/vnd.MyCustomType-v1+json;charset=utf-8" and of course it doesn't work with current implementation. Have tried different solutions, but nothing seems to work. Any ideas?
I'm using play 2.1

The source for the json body parser looks like this:
def json(maxLength: Int): BodyParser[JsValue] = when(
_.contentType.exists(m => m.equalsIgnoreCase("text/json") || m.equalsIgnoreCase("application/json")),
tolerantJson(maxLength),
createBadResult("Expecting text/json or application/json body")
)
tolerantJson is, itself, a body parser that does the json parsing without a check of the content-type header, so you should just be able to use that to parse your request instead of parse.json.
If you want to go further and have a parser that checks your specific content-type header then you could use
when(
_.contentType.exists(m => m.equalsIgnoreCase(expectedContentType)),
tolerantJson(maxLength),
createBadResult("Wrong content type")
)
to create your own parser.

Related

Lagom - Add header to response in service call composition

i want to write code which will refresh cookie (via set-cookie http header) in Lagom.
For clarification Cookie is an encoded string (for example AES).
Lets take lagom service call composition for authentication from Implementing services and edit it
def authenticated[Request, Response](
serviceCall: User => ServerServiceCall[Request, Response]
) = ServerServiceCall.composeAsync { requestHeader =>
//Get cookie from header and decode it
val cookie = decodeCookie(requestHeader)
//Get user based on cookie decode function
val userLookup = getUser(cookie)
userLookup.map {
case Some(user) =>
serviceCall(user)
case None => throw Forbidden("User must be authenticated")
}
}
It is possible to manipulate serviceCall(user) response headers?
I tried something like this:
serviceCall( employee ).handleResponseHeader { case (responseHeader, response) =>
responseHeader.withHeader("Set-Cookie",encodeCookie("NewCookieStringExample")) // Add header
response
}
But function handleResponseHeader requires only response[T] as result and header would not be changed because is immutable.
I know that i can pass cookie to serviceCall(user) and in every service call implementation return tuple with ResponseHeader and Response but this will impact all endpoints and will add much more code.
Use of HeaderFilter is possible too but this would decode and encode cookie twice in one request (in header filter and in authenticated service call composition )
Any tips?
You can return the modified Header and the Response as a Tuple:
serviceCall( employee ).handleResponseHeader((responseHeader, response) => {
val modifiedHeader = responseHeader.withHeader("Set-Cookie",encodeCookie("NewCookieStringExample")) // Add header
(modifiedHeader, response)
})
By the way, The provided example does not compile for me. composeAsync wants a Future[ServerServiceCall[...]].

Akka Http - Getting Multipart Form Data

I am creating Post Call using Akka-Http where user will fill the form and make a request.
I want to convert this form data to Scala Map[String, String]
Can any one tell how to do this.
here is the code Snippet
post {
entity(as[Multipart.FormData]) { body =>
complete { //How to process Multi Part Form data to Map
}
}
}
Thanks
Looks like you're looking for the formFieldMap directive.
(post & formFieldMap) { fields =>
doStuffWith(fields)
complete(...)
}
See the docs for more info.

Send POST request with a body using scala and play framework

I`m trying to send post request to external url using play framework and scala. I want to add some parameters to the body also.
I want to send a post request to "http://www.posonlinedemo.tk" with parameters TransactionNo='T10000' and reqtype='T'
how could i do it?
here is my Action
def test(para:String) = Action {
val url: Option[String] = Some("http://www.posonlinedemo.tk")
url match {
case Some(url) => Redirect(url)
case None => NotFound("This URL leads nowhere. :(")
}
}
You can use the Play WS API.
As you can see in the documentation, it is that simple:
ws
.url(url)
.post(Map(
"TransactionNo" -> Seq("T10000"),
"reqtype" -> Seq("T")))
Don't forget to add ws to your library dependencies.

Akka HTTP set response header based on result of Future

I'm designing a REST service using Akka-HTTP 2.0-M2 and have come across a situation where I'd like to supply additional headers which are dependent upon the reply of the queried Actor.
Currently, I have the following...
val route = {
path("oncologist") {
get {
parameters('active.as[Boolean].?, 'skip.as[Int].?, 'limit.as[Int].?).as(GetAllOncologists) {
req =>
complete {
(oncologistActor ? req).mapTo[OncologistList]
}
}
}
}
While this is returning without issue. I'd like to move some of the properties of OncologistList into the response header rather than returning them in the body. Namely, I'm returning total record counts and offset and I would like to generate a previous and next URL header value for use by the client. I'm at a loss on how to proceed.
I think you can use the onComplete and respondWithHeaders directives to accomplish what you want. The onComplete directive works with the result of a Future which is exactly what ask (?) will return. Here is an example using a case class like so:
case class Foo(id:Int, name:String)
And a simple route showing onComplete like so:
get{
parameters('active.as[Boolean].?, 'skip.as[Int].?, 'limit.as[Int].?).as(GetAllOncologists) { req =>
val fut = (oncologistActor ? req).mapTo[Foo]
onComplete(fut){
case util.Success(f) =>
val headers = List(
RawHeader("X-MyObject-Id", f.id.toString),
RawHeader("X-MyObject-Name", f.name)
)
respondWithHeaders(headers){
complete(StatusCodes.OK)
}
case util.Failure(ex) =>
complete(StatusCodes.InternalServerError )
}
}
}
So if we get a successful result from the ask on oncologistActor we can then leverage the respondWithHeaders to add some custom headers to the response. Hopefully this is what you were looking for.

How can my Play 2 app respond to different "Accept" headers from the client?

In Rails, I was able to do something similar to the following:
respond_to do |format|
format.xml { ... }
format.json { ... }
end
and the appropriate block would be executed based on what the client supplied in the Accept header.
How can I do the same thing in Play 2.0 (Scala)?
I'd look to do something that looks roughly like this:
try {
Resources.delete(id)
Ok("done")
}
catch {
case e: ClientReportableException =>
?? match {
case "application/xml" => Ok(<error>{e.message}</error>)
case "application/json" => Ok(...)
}
}
Is there a Play idiom for this, or do I just fetch the value of the Accept header from the request?
In Play 2.1 you can write the following:
request match {
case Accepts.Xml() => Ok(<error>{e.message}</error>)
case Accepts.Json() => Ok(…)
}
The cases statements are tried in the order they are written, so if your client sets the HTTP Accept header to */* the first one will match (in this example case Accepts.Xml()). So, you usually want to write the Accepts.Html() case first because browsers set the Accept header to */*.
(Note: you may also be interested in this answer for a similar question in Java)
I have just released a Play! 2.0 module for content negotiation called mimerender (http://github.com/martinblech/play-mimerender).
The idea is that you have to define a mapping from your domain classes to different representations:
val m = mapping(
"text/html" -> { s: String => views.html.index(s) },
"application/xml" -> { s: String => <message>{s}</message> },
"application/json" -> { s: String => toJson(Map("message" -> toJson(s))) },
"text/plain" -> identity[String]_
)
Once you have done that once, you can reuse that mapping throughout all your controllers:
object Application extends Controller {
def index = Action { implicit request =>
m.status(200)("Hello, world!")
}
}
Please note it's a very early release and has only been tested on Play 2.0.4