I am trying to define a webservice, using Scalatra, where the parameters are passed in in the body, preferably as JSON, not having everything on the url, as I have it now.
So, I would like this test to pass, but the commented out code is what passes currently. The non-commented code isn't JSON, but I also am not certain how I would pass JSON for testing, as put requires an Iterable in the second parameter.
class WebAppSpec extends MutableScalatraSpec {
addServlet(classOf[WebApp], "/*")
"PUT /phaseupdate" should {
"return status 200" in {
//put("/phaseupdate/test1/address1/starting/10") {
put("/phaseupdate", Map("filename" -> "test1", "entryaddress" -> "address1","name" -> "starting","percentcomplete" -> "10")) {
status must_== 200
}
}
}
My current definition, which is wrong, is:
put("/phaseupdate/:filename/:entryaddress/:name/:percentcomplete") {
val filename = params("filename")
val entryaddress = params("entryaddress")
val name = params("name")
val percentcomplete = params("percentcomplete")
So how do I define my put service to just call it with PUT /phaseupdate and have the parameters in the body?
I am trying to limit what is going into the webserver access log, basically.
The solution is to do this:
put("/phaseupdate") {
val filename = if (params("filename").indexOf('.') > -1) params("filename").substring(0, params("filename").indexOf('.')) else params("filename")
val entryaddress = params("entryaddress")
val name = params("name")
val percentcomplete = params("percentcomplete")
Basically, params() can read in what was passed.
The specs2 test is, and if this is followed by the get it returns the correct information.
"PUT /phaseupdate" should {
"return status 200" in {
put("/phaseupdate", Map("filename" -> "test1", "entryaddress" -> "address1", "name" -> "starting", "percentcomplete" -> "10")) {
status must_== 200
}
}
}
Related
I created simple project to check libraries like RxAlamofire and AlamofireObjectMapper. I have simple ApiService with one endpoint where is PHP script which works properly and returns JSON. I want call to recipeURL and I use flatMap operator to get response and provide it into Mapper where I should get Recipe object. How I can to do that?
Or is there other way?
class ApiService: ApiDelegate{
let recipeURL = "http://example.com/test/info.php"
func getRecipeDetails() -> Observable<Recipe> {
return request(.get, recipeURL)
.subscribeOn(MainScheduler.asyncInstance)
.observeOn(MainScheduler.instance)
.flatMap({ request -> Observable<Recipe> in
let json = ""//request.??????????? How to get JSON response?
guard let recipe: Recipe = Mapper<Recipe>().map(JSONObject: json) else {
return Observable.error(ApiError(message: "ObjectMapper can't mapping", code: 422))
}
return Observable.just(recipe)
})
}
}
From RxAlamofire's readme, it seems a method json(_:_:) exists in the library.
Typically, you'd rather use map instead of flatMap to transform the returned data to another format. flatMap would be useful if you needed to subscribe to a new observable (for example, doing a second request using part of the result from the first one).
return json(.get, recipeURL)
.map { json -> Recipe in
guard let recipe = Mapper<Recipe>().map(JSONObject: json) else {
throw ApiError(message: "ObjectMapper can't mapping", code: 422)
}
return recipe
}
In the following code, I am getting a token in the first Gatling request, saving it in a variable named auth. However, when I try to use it in the second request, it is sending empty string in place of auth variable. So for some reason, the auth string is not being updated till the time it is being used in the second request. Can anyone suggest any workaround so that I can use the value returned in one request into another request?
Code:
val headers_10 = Map("Content-Type" -> "application/x-www-form-urlencoded")
var a= "qwerty91#gmail.com"
var auth = ""
val scn = scenario("Scenario Name") // A scenario is a chain of requests and pauses
.exec(http("request_1") // Here's an example of a POST request
.post("/token")
.headers(headers_10)
.formParam("email", a)
.formParam("password", "password")
.transformResponse { case response if response.isReceived =>
new ResponseWrapper(response) {
val a = response.body.string
auth = "Basic " + Base64.getEncoder.encodeToString((a.substring(10,a.length - 2) + ":" + "junk").getBytes(StandardCharsets.UTF_8))
}
})
.pause(2)
.exec(http("request_2")
.get("/user")
.header("Authorization",auth)
.transformResponse { case response if response.isReceived =>
new ResponseWrapper(response) {
val a = response.body.string
}
})
You should store the value you need in the session. Something like this will work, although you'll have to tweak the regex and maybe some other details:
val headers_10 = Map("Content-Type" -> "application/x-www-form-urlencoded")
var a= "qwerty91#gmail.com"
var auth = ""
val scn = scenario("Scenario Name") // A scenario is a chain of requests and pauses
.exec(http("request_1") // Here's an example of a POST request
.post("/token")
.headers(headers_10)
.formParam("email", a)
.formParam("password", "password")
.check(regex("token: (\\d+)").find.saveAs("auth")))
.pause(2)
.exec(http("request_2")
.get("/user")
.header("Authorization", "${auth}"))
Here's the documentation on "checks", which you can use to capture values from a response:
http://gatling.io/docs/2.2.2/http/http_check.html
Here is the documentation on the gatling EL, which is the easiest way to use session variables (this is the "${auth}" syntax in the last line above):
http://gatling.io/docs/2.2.2/session/expression_el.html
I develop Rest API with scala and play framework.
In my product controller, I do validation of parameters received.
In case they fail from some reason, I would like to response with BadRequest in the middle of the function and not in the last line as scala works..
In the code below - Code continues running to the Ok line.. which is wrong, I want to return !
def getProduct(lang: String, t: String, ids: String) = Action {
val productIdsList = ids.split(",").toList
if (productIdsList.length.equals(1) && productIdsList(0).equals("")) //Validate input params are product Ids and not empty !
{
var errorResponse:ErrorResponse[String] = ErrorResponse(ErrorCode.GeneralError, "No products IDs", 500)
BadRequest(Json.toJson(errorResponse))//maybe return BadRequest(Json.toJson(errorResponse) ??
}
val results = productService.getProducts(GetProductsRequest(lang,t,productIdsList));
Ok(Json.toJson(results))
// TODO: handle error
}
If implemented as:
return BadRequest(...)
It reply with error:
"method getProduct has return statement; needs result type"
I Understand this is bad practice, so what is the best practice for quitting the function without finishing it (and not throwing exceptions..)
Just put an else branch, so there's nowhere to continue:
def getProduct(lang: String, t: String, ids: String) = Action {
val productIdsList = ids.split(",").toList
if (productIdsList.length.equals(1) && productIdsList(0).equals("")){ //Validate input params are product Ids and not empty !
var errorResponse:ErrorResponse[String] = ErrorResponse(ErrorCode.GeneralError, "No products IDs", 500)
BadRequest(Json.toJson(errorResponse))//maybe return BadRequest(Json.toJson(errorResponse) ??
}else{
val results = productService.getProducts(GetProductsRequest(lang,t,productIdsList));
Ok(Json.toJson(results))
// TODO: handle error
}
}
I use The Play WS API from PlayFramework to communicate with external API.
I need to process the received data, but don't know how. I get a response, and I want to pass it to other function like an JSON Object. How I can achieve that?
Code I use you can see below.
Thanks!
def getTasks = Action {
Async {
val promise = WS.url(getAppProperty("helpdesk.host")).withHeaders(
"Accept" -> "application/json",
"Authorization" -> "Basic bi5sdWJ5YW5vdjoyMDEzMDcwNDE0NDc=" ).get()
for {
response <- promise
} yield Ok((response.json \\ "Tasks"))
}
}
I get a response, and I want to pass it to other function like an JSON Object.
I'm not sure I understand your question, but I'm guessing you want to transform the json you receive from the WS call prior to returning to the client, and that this transformation could take several lines of code. If this is correct, then you just need to add curly brackets around your yield statement so you can do more work on the response:
def getTasks = Action {
Async {
val promise = WS.url(getAppProperty("helpdesk.host")).withHeaders(
"Accept" -> "application/json",
"Authorization" -> "Basic bi5sdWJ5YW5vdjoyMDEzMDcwNDE0NDc=" ).get()
for {
response <- promise
} yield {
// here you can have as many lines of code as you want,
// only the result of the last line is yielded
val transformed = someTransformation(response.json)
Ok(transformed)
}
}
}
I took a look at the doc, and you could try:
Async {
WS.url(getAppProperty("helpdesk.host")).withHeaders(
"Accept" -> "application/json",
"Authorization" -> "Basic bi5sdWJ5YW5vdjoyMDEzMDcwNDE0NDc=" ).get().map{
response => Ok(response.json \\ "Tasks")
}
}
I am using databinder dispatch for making HTTP requests which works nicely, as long as the web server returns a 404.
If the request fails, the web server returns a 403 status code and provides a detailed error message in the response body as XML.
How to read the xml body (regardless of the 403), e.g. how can I make dispatch ignore all 403 errors?
My code looks like this:
class HttpApiService(val apiAccount:ApiAccount) extends ApiService {
val http = new Http
override def baseUrl() = "http://ws.audioscrobbler.com/2.0"
def service(call:Call) : Response = {
val http = new Http
var req = url(baseUrl())
var params = call.getParameterMap(apiAccount)
var response: NodeSeq = Text("")
var request: Request = constructRequest(call, req, params)
// Here a StatusCode exception is thrown.
// Cannot use StatusCode case matching because of GZIP compression
http(request <> {response = _})
//returns the parsed xml response as NodeSeq
Response(response)
}
private def constructRequest(call: Call, req: Request, params: Map[String, String]): Request = {
val request: Request = call match {
case authCall: AuthenticatedCall =>
if (authCall.isWriteRequest) req <<< params else req <<? params
case _ => req <<? params
}
//Enable gzip compression
request.gzip
}
}
I believe something like this works:
val response: Either[String, xml.Elem] =
try {
Right(http(request <> { r => r }))
} catch {
case dispatch.StatusCode(403, contents) =>
Left(contents)
}
The error will be in Left. The success will be in Right. The error is a String that should contain the XML response you desire.
If you need more, I believe you can look at HttpExecutor.x, which should give you full control. It's been a while since I've used dispatch, though.
Also, I'd suggest using more val's and less var's.