Getting an HTTP response as Array[Byte] with Scala and Dispatch - scala

I'm trying to download the response of an HTTP GET request as an Array[Byte] in Scala using dispatch, but the documentation is not helping and online searches didn't turn out to be helpful.
Additionally, I need to retrieve the value of a header in the response.
Could anyone please provide a working snippet, possibly with a custom header?
Thanks in advance!

Came up with my own way:
val (someHeaderVal, buf) = Http x (url(fileUrl) <:< Map("ACustomHeader" -> "MyValue") >:+ {
(headers, req) => req >> {
stream => (headers("ResponseCustomHeader").head, IOUtils.toByteArray(stream))
}
})
This seems to work just fine.

Related

Print the JSON response from GET request in Finagle

I am trying to do a GET request and print the JSON response that I get back. The JSON response should look like this.
{
"request_status": "Success",
"workflow_step": "End"
}
Here's my code:
handle(GetStatus) { args: GetStatus.Args =>
val client: Service[http.Request, http.Response] =
Http.client.withTlsWithoutValidation.newService("idm-preprod-fe1.twitter.biz:80")
val request = http.Request(
http.Method.Get,
"/plugin/rest/groupmanagement/getStatus/Create Group Request for mygroup (1638800484991)")
request.host = "idm-preprod-fe1.twitter.biz"
Future.value(GetStatusResponse(Option(client(request).toString)))
}
Now when my client sends the request to the server, I want to print the JSON but the format that I am getting is. Can someone please guide me as how to achieve this.
Promise#1589131174(state=Transforming(WaitQueue(size=1),Promise#1823443423(state=Transforming(WaitQueue(size=1),Promise#859399396(state=Transforming(WaitQueue(size=4),Promise#1441370332(state=Transforming(WaitQueue(size=2),Promise#1459834(state=Transforming(WaitQueue(size=2),Promise#156947070(state=Transforming(WaitQueue(size=1),Promise#1739595981(state=Transforming(WaitQueue(size=1),Promise#273198152(state=Transforming(WaitQueue(size=1),Promise#478329071(state=Transforming(WaitQueue(size=2),Promise#1175786031(state=Transforming(WaitQueue(size=1),Promise#1749285277(state=Transforming(WaitQueue(size=1),Promise#1733124454(state=Transforming(WaitQueue(size=1),Promise#1257379837(state=Transforming(WaitQueue(size=1),Promise#1192050340(state=Transforming(WaitQueue(size=1),Promise#1114225943(state=Transforming(WaitQueue(size=1),Promise#1417620904(state=Transforming(WaitQueue(size=1),Promise#1638767611(state=Interruptible(WaitQueue(size=2),<function1>))))))))))))))))))))))))))))))))))
client(request) is giving you a Future[http.Response]: it represents a response that will be available some time in the future.
You cannot use toString() on it directly because it's a Future and also because even if it was not a Future it would be a Response, which is a whole HTTP response, not only the body.
I'd recommend reading more about how Future works and how to use it.
In your case, you should do something like following (pseudo code as I'm not familiar with Twitter's Future):
client(request).map { httpResponse =>
val responseBody = httpResponse.body
GetStatusResponse(Option(responseBody))
}

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.

Idiomatic way to create a basic HTTP Post request with Akka HTTP

I'm trying to figure out how to create a basic HTTP POST request with the Akka HTTP library. This is what I came up with:
val formData = Await.result(Marshal(FormData(combinedParams)).to[RequestEntity], Duration.Inf)
val r = HttpRequest(POST, url, headers, formData)
The thing is that it seems a bit non-idiomatic to me. Are there other ways to create a HttpEntity from FormData? Especially the fact that I have to use Await or return a Future even though the data is readily available seems overly complex for such a simple task.
You can use Marshal in a for comprehension with other Futures, such as the ones you need to send the request and unmarshall the response:
val content = for {
request <- Marshal(formData).to[RequestEntity]
response <- Http().singleRequest(HttpRequest(method = HttpMethods.POST, uri = s"http://example.com/test", entity = request))
entity <- Unmarshal(response.entity).to[String]
} yield entity
Apparently a toEntity method was added to the FormData class at some point. So this now seems like the simplest solution to the problem:
val formData = FormData(combinedParams).toEntity
val r = HttpRequest(POST, url, headers, formData)
You can also use RequestBuilding:
Http().singleRequest(RequestBuilding.Post(url, formData)).flatMap(Unmarshal(_).to[String])

PlayFramework Testing: Uploading File in Fake Request Errors

I want to test my method, which requires uploading a file. It is initialized like this:
val tempFile = TemporaryFile(new java.io.File("/home/ophelia/Desktop/students"))
val part = FilePart[TemporaryFile](
key = "students",
filename = "students",
contentType = Some("text/plain"),
ref = tempFile)
val files = Seq[FilePart[TemporaryFile]](part)
val formData = MultipartFormData(
dataParts = Map(),
files = Seq(part),
badParts = Seq(),
missingFileParts = Seq())
I pass it into the FakeRequest:
val result = route(
FakeRequest(POST, "/api/courses/"+"4f3c4ec9-46bf-4a05-a0b2-886c2040f2f6"+"/import" )
.withHeaders("Authorization" -> ("Session " + testSessionA.id.string))
.withMultipartFormDataBody(formData)
)
But when I run the test I get the following error:
Cannot write an instance of play.api.mvc.AnyContentAsMultipartFormData to HTTP response. Try to define a Writeable[play.api.mvc.AnyContentAsMultipartFormData]
What am I doing wrong and how to fix it? I looked on the internet, I didnt find any useful way to understand and resolve this problem.
It's important to remember that http requests are entirely text. route() takes an implicit Writeable to convert the body type of the provided request into text. Without the right Writeable, there is no way to know how to turn MultipartFormData into a request body.
There doesn't seem to be a Writeable for MultipartFormData, but you can provide your own. jroper has a great Writeable you could use for reference. (EDIT: That code is buggy, here's a working Writeable for AnyContentAsMultipartFormData)
Once you have your Writeable, you will need to make it accessible to your call to route(). Bear in mind, you currently have a FakeRequest[AnyContentAsMultipartFormData], not a FakeRequest[MultipartFormData]. You can either convert your request first:
val request = FakeRequest(POST,
"/api/courses/"+"4f3c4ec9-46bf-4a05-a0b2-886c2040f2f6"+"/import" )
.withHeaders("Authorization" -> ("Session "))
.withMultipartFormDataBody(formData)
route(request.map(_.mdf).asInstanceOf[FakeRequest[MultipartFormData[TemporaryFile]]])
or make your Writeable a Writeable[AnyContentAsMultipartFormData].
route for a given Request[T] requires an implicit parameter of type Writeable[T] that knows how to serialize the request body, because it will actually call the controller action just like an actual web request would, by pushing bytes onto it.
The problem is that there is no Writeable[MultipartFormData] predefined (you can see which are in play.api.test.Writeables).
This means you basically have two options:
write your own Writeable that serializes a MultipartFormData into bytes
Skip the routing part and call the action directly instead, like in the accepted answer in Play Framework Testing using MultipartFormData in a FakeRequest. This way of testing actions takes a shortcut and does not actually serialize and deserialize the request.
IMHO the first option is way too much pain for the gain, but if you go down that road, maybe contribute it to play when you succeed.
One of the possible solutions is to use wsUrl. For example
"File uploading action" should {
"upload sent file and result in ID" in {
val file = Paths.get(getClass.getResource("/1.txt").toURI)
val action = wsUrl("/upload").post(Source.single(FilePart("file", "hello.txt", Option("text/plain"), FileIO.fromPath(file))))
val res = Await.result(action, timeout)
res.status mustBe OK
res.body contains "123"
}
}

Spray testing basicauth from js html

I have code like:
https://gist.github.com/daaatz/7665224
but dont know how to test request.
Trying mydomain/secured?user=John&password=p4ssw0rd etc but nothing works.
Can some one tell me or show example in js+html how to check is it working fine ?
Thanks
I've never used BasicAuth in Spray, so i'm not sure if this would be the complete answer, but i hope this will help you.
At first. in spray there is a great spray-testkit written on top of akka testkit. You should definitely check out SecurityDirectives test on github, this will show you how to test basic authentication. A little example, to make this simpler:
As for your route example, i would better edit to the following one:
val myRoute =
(path("secured") & get) {
authenticate(BasicAuth(myUserPassAuthenticator _, realm = "secure site")) {
userName => complete(s"The user is '$userName'")
}
}
}
Adding get directive will specify that this route expects a Get request and sealRoute is obsolete cause RejectionHandler and ExceptionHandler are provided implicitly with runRoute. It is used only in tests, if you want wo check exceptions/rejections.
Now in your tests you should construct auth entities, similar to the test one:
val challenge = `WWW-Authenticate`(HttpChallenge("Basic", "Realm"))
val doAuth = BasicAuth(UserPassAuthenticator[BasicUserContext] { userPassOption ⇒
Future.successful(Some(BasicUserContext(userPassOption.get.user)))
}, "Realm")
And you test case:
"simple auth test" in {
Get("security") ~> Authorization(BasicHttpCredentials("Alice", "")) ~> {
authenticate(doAuth) { echoComplete }
} ~> check { responseAs[String] === "BasicUserContext(Alice)" }
}
In Get("security") specifies that your test will send a Get request on "/security", then add Authorization to the test request, some action and the check part to test the request.
I've never tried to test BasicAuth, so there could be some mistakes.
I would look into CURL for testing routes in web applications, but I've also used the chrome extension Postman with great results as well.