Akka Http - Getting Multipart Form Data - scala

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.

Related

How to read query parameters in akka-http?

I know akka-http libraries marshal and unmarshal to class type while processing request.But now, I need to read request-parameters of GET request. I tried parameter() method and It is returning ParamDefAux type but i need those values as strings types
I check for answer at below questions.
How can I parse out get request parameters in spray-routing?
Query parameters for GET requests using Akka HTTP (formally known as Spray)
but can't do what i need.
Please tell me how can i extract query parameters from request. OR How can I extract required value from ParamDefAux
Request URL
http://host:port/path?key=authType&value=Basic345
Get method definition
val propName = parameter("key")
val propValue = parameter("value")
complete(persistanceMgr.deleteSetting(propName,propValue))
My method declarations
def deleteSetting(name:String,value:String): Future[String] = Future{
code...
}
For a request like http://host:port/path?key=authType&value=Basic345 try
path("path") {
get {
parameters('key.as[String], 'value.as[String]) { (key, value) =>
complete {
someFunction(key,value)
}
}
}
}
Even though being less explicit in the code, you can also extract all the query parameters at once from the context. You can use as follows:
// Previous part of the Akka HTTP routes ...
extract(_.request.uri.query()) { params =>
complete {
someFunction(key,value)
}
}
If you wish extract query parameters as one piece
extract(ctx => ctx.request.uri.queryString(charset = Charset.defaultCharset)) { queryParams =>
//useyourMethod()
}

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.

Change a body Field name in a Post in Spray

I'm thinking to replace a field called "type" in a JSON in a POST with somethig like this
def rawJson = extract { _.request.entity.asString}
post {
rawJson { json =>
val new json = println(json.replace("\"type\":", "\"eventType\":"))}
}
And now, with this new JSON I want to reinject the POST to trate it like a new call.
I know "redirect" but I don't see the way to use it in this case.
Thanks!
I'll answer my own question. I hope someone else can found it useful:
I've change the post on-the-fly. My problem was that I was using: entity(as[Event]) and I was unable to transform it. But deserializing it like a JObject I have the control of the fields. It's a very powerful tool.
post {
entity(as[JObject]) {
eventO =>
val nevent: json4s.JValue = eventO.mapField(x => if (x._1=="type") ("eventType",x._2) else (x._1,x._2))
val event = nevent.extract[Event]
handlePerRequest {
RouteMessageToCluster(event)
}
}
}

Grails - render validation errors as JSON

I'm building a RESTful API and the endpoints I'm creating are using command objects to validate the request data. I'm trying to figure out the best way to render the validation errors as json. For xml responses I followed the recommendation in the Grails in Action book and did...
response.status = 403
render(contentType: "text/xml") {
errors {
eventSaleDataCommand.errors.fieldErrors.each { err ->
field(err.field)
message(g.message(error: err))
}
}
}
This works well for rendering xml responses so I'm wondering what the recommended approach for rendering json responses is?
I wanted to have some control of how the error gets displayed so for the json response I added:
def results = eventSaleDataCommand.errors.fieldErrors.toList()
def errors = []
for (error in results) {
errors.add([
'type' : 'invalid_entry',
'field' : error.field,
'rejected_value': error.rejectedValue,
'message' : error.defaultMessage
])
}
render errors as JSON
Problem with this approach is I'm using the Joda time plugin so I'm getting the following exception when I try to render the map as JSON:
Class org.codehaus.groovy.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller can not access a member of class org.joda.time.tz.DateTimeZoneBuilder$PrecalculatedZone with modifiers "public".
Anyone know of a way around this?
How about?
render eventSaleDataCommand.errors.fieldErrors as JSON

What is the correct way to process REST requests in Contoller

I have created a controller for an "applications" table. The web and REST interfaces are working but I think the add and edit functions should be better.
When I tested add and edit I found the data needed to be posted in web FORM format (not JSON).
I found I needed to use "$this->request->input('json_decode')" in the save to decode the JSON data. I thought this happened automagically.
This function now works for add (edit is similar) and displays my json/add.ctp so I can return the successful record to the user.
public function add() {
if ($this->request->is('post')) {
$this->Application->create();
//Is the request REST passing a JSON object?
if (preg_match('/\.json/', $this->request->here)){
//This is a REST call
$this->set('status', $this->Application->save($this->request->input('json_decode')));
} else {
//This is an interactive session
if ($this->Application->save($this->request->data)) {
$this->Session->setFlash(__('The application has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The application could not be saved. Please, try again.'));
}
}
}
}
I used the "$this->request->here" to see if it ends in ".json". Is this the "correct" way to process the REST call?
There is an entire section in the CakePHP Book for this. I think it will answer your question(s):
http://book.cakephp.org/2.0/en/development/rest.html
The question is, does your action accept JSON data & Form Data? or just JSON data?
The .json is purely for the output of your data, you are able to send JSON data with the .xml extension, the difference being once the data is sterilised, it will output in XML.
if($this->request->is('post')) {
if(empty($this->request->data)){
$data = $this->request->input('json_decode', TRUE);
} else {
$data = $this->request->data;
}
} else {
$data = $this->params['url'];
}
Above is kind of what you should be doing, check if the data comes from a form, if not, decode JSON, and if it is NOT a POST, save parameters that have been included into the URL.
I am not saying the above is the "right" way to do it, but thats probably what you are looking for.