How to read query parameters in akka-http? - scala

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()
}

Related

Gatling httpRequest with dynamic method from collection

I want to build a Gatling scenario from a collection of structured data (StructuredDataCollection).
My problem is, that I'm unable to pass in the "method" (as in HTTP method) from an element from the collection into the http call of the actual test.
Here's a code snippet.
def testScenario(duration: Int) = scenario("SO").during(duration) {
exec {
session => {
val test = StructuredDataCollection.next()
val title = test.title
val method = test.method // Not being used, because it does not work like that :(
val endpoint = test.endpoint
val requiredParameters = test.requiredParameters
val code = test.code
session
.set("title", title)
.set("methodFUG", method).set("endpoint", endpoint)
.set("requiredParameters", requiredParameters)
.set("code", code)
}
}
.exec(
http("${title}")
.httpRequest("get", "${endpoint}") // TODO: method can't be passed in as an expression.
.queryParamMap("${requiredParameters}")
.check(status.is("${code}"))
)
}
As you can see, I've hard-coded "get", but I'll need that to be replaced with the actual value from the method property from the current selected item from the collection.
Unfortunately, Gatling's DSL isn't available in all the places where you'd expect it to be, and it's just reading that as a string.
It took me some time to realize, that
http("${title}").httpRequest("${methodFUG}", "${endpoint}") will actually make a HTTP call with the invalid method "${methodFUG}" and not the value from the collection element, which could be "GET", "POST", "PUT", "DELETE", and so on.
httpRequest signature is (method: String, url: Expression[String]), see documentation.
It cannot take an Expression, only a static String.

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.

Gatling Conditional on Response Body

I am currently using Gatling and I have a scenario whereby I perform a number of GET requests and depending on the body of the responses I would like to perform a different scenario.
I have this at the moment that doesn't appear to work as expected -
val repeatSpin = scenario("repeatScenario1").repeat(10) {
exec(
scenario1
)
.doIf(bodyString => bodyString.equals("<SwitchEvent/>")){
exec(scenario2)
}
}
What am I doing wrong?
It looks like you've got the .doIf parameters wrong - it either takes a key in the session and the value you expect, like:
.doIf("${bodyString}", "<SwitchEvent/>") { myChain }
Or, an Expression[Boolean] - the argument you get is the session; to get values out of a session you do something like session("bodyString").as[String]. So, passing a function to the doIf could look like
.doIf(session => session("bodyString").as[String].equals("<SwitchEvent/>")) { myChain }

Gatling 2 dynamic queryParam on each request

I am trying to run a load test using Gatling 2. I need to generate one of the query parameters dynamically on each request.
My scenario is defined like this:
val scn = scenario("Load Test Scenario")
.exec(
http("Test API")
.post(url)
.body(StringBody("Some XML"))
.queryParam("x", DigestUtils.md5Hex(generateX().getBytes("UTF-8")))
)
def generateX() : String = {
// generate random string and return
}
This only calls generateX once and uses the result in each request. Is there anyway to have the generateX call on every request?
You have to pass a function, not a value. See Gatling documentation about Expression.
Here, you can just discard the session input parameter as you don't use it, so you can simply write:
.queryParam("x", _ => DigestUtils.md5Hex(generateX().getBytes("UTF-8")))

How can I parse out get request parameters in spray-routing?

This is what the section of code looks like
get{
respondWithMediaType(MediaTypes.`application/json`){
entity(as[HttpRequest]){
obj => complete{
println(obj)
"ok"
}
}
}
}~
I can map the request to a spray.http.HttpRequest object and I can extract the uri from this object but I imagine there is an easier way to parse out the parameters in a get request than doing it manually.
For example if my get request is
http://localhost:8080/url?id=23434&age=24
I want to be able to get id and age out of this request
Actually you can do this much much better. In routing there are two directives: parameter and parameters, I guess the difference is clear, you can also use some modifiers: ! and ?. In case of !, it means that this parameter must be provided or the request is going to be rejected and ? returns an option, so you can provide a default parameter in this case. Example:
val route: Route = {
(path("search") & get) {
parameter("q"!) { query =>
....
}
}
}
val route: Route = {
(path("search") & get) {
parameters("q"!, "filter" ? "all") { (query, filter) =>
...
}
}
}