Methods to insert Oauth headers in Scala Dispatch 0.9.5? - scala

Using the rather simple and elegant Scala Dispatch HTTP library. Since the Twitter Search API is now using OAuth 1.0A, I obviously need to start injecting Consumer and AccessToken information. I've got a simple request below:
val request = url("https://api.twitter.com/1.1/search/tweets.json?q=%23%sresult_type=mixed&count=4" format w.queryValue)
val response = Http(request OK as.String)
What's a way to add headers to this if I already know my Consumer and AccessToken information? The documentation is rather scarce. Thanks!

I'm not familiar with the OAuth API, but Dispatch allows you to add arbitrary HTTP Request headers with the <:< method/operator.
So mashing together your code example above and this "Authorizing a request" example from Twitter's Developer site, you might get something like this:
val authentication = """OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0""""
val request = url("https://api.twitter.com/1.1/search/tweets.json?q=%23%sresult_type=mixed&count=4" format w.queryValue)
val authHeader = Map("Authentication" -> authentication)
val requestWithAuthentication = request <:< authHeader
val response = Http(requestWithAuthentication OK as.String)
I haven't verified whether this actually works, but hopefully it should get you going in the right direction.

I am doing it like this with dispatch:
private def buildSearchReq(searchTerm: String, lat: Double, long: Double): Req = {
val consumer = new ConsumerKey(consumerKey, consumerSecret)
val requestToken = new RequestToken(token, tokenSecret)
val req = url(searchUrl)
.addQueryParameter("term", searchTerm)
.addQueryParameter("radius_filter", "40000")
.addQueryParameter("ll", s"$lat,$long")
new SigningVerbs(req).sign(consumer, requestToken)
}
You could also do something more like this if you wanted:
private def buildSearchReq(searchTerm: String, lat: Double, long: Double): Req = {
val req = url(searchUrl) <<? Map("term" -> searchTerm, "radius_filter" -> "40000", "ll" -> s"$lat,$long")
new SigningVerbs(req).sign(new ConsumerKey(consumerKey, consumerSecret), new RequestToken(token, tokenSecret))
}
There are probably even more terse ways of doing it, but you get the idea.

Related

Scala testing Web Service Client for POST request

So the Play documentation you can find here gives a very simple example for a GET call without anything like auth header or parameters.
Could somebody help me figure out how to use a similar strategy for something more complex like a POST request with JSON data as body and auth header required? I can't get it to work right now.
I want to know how to test a client using ws to do it's external http requests.
Thanks
Here is a snippet of code from one of my projects which sends sms via twilio api:
class SmsServiceImpl #Inject()(config: Configuration, ws: WSClient) extends SmsService {
val twilloAccountSid = config.getString("twillo.accountSid").get
val twilloAuthToken = config.getString("twillo.authToken").get
val smsApiUrl = config.getString("twillo.apiBaseUrl").get + "/" +twilloAccountSid+"/Messages.json"
override def send(phone: String, message: String): Future[Unit] = {
val data = Map(
"To" -> Seq(phone),
"From" -> Seq(config.getString("twillo.fromPhone").get),
"Body" -> Seq(message)
)
val response: Future[WSResponse] = ws.url(smsApiUrl).withAuth(twilloAccountSid, twilloAuthToken, WSAuthScheme.BASIC).post(data)
response.map { response =>
response.status match {
case 201 => Unit
case _ => throw new SmsSendingException(s"Failed to send sms. Got https status: ${response.status}")
}
}
}
It is POST request with authentication.

Endpoint requires authentication Rest API Spray

I would like to consume some resources from This Rest API
But it seems that I need some Authorization. And actually as a beginner I don't know how to access to this endpoint using Spray.
A simple example of Spray Client:
val pipeline = sendReceive ~> unmarshal[GuildwarsApiResult]
val responseFuture = pipeline {
Get("https://api.guildwars2.com/v2/commerce/listings/46741")
}
Thanks !
I see a lot of questions lately from people who want to use API of GuilWars. Was it recently created ?
As per your question you need to specify HTTP header with API token as stated in documentation for POST requests. For GET requests you should pass token in URL.
This shows how to create and use custom http header.
object ApiTokenHeader extends ModeledCustomHeaderCompanion[ApiTokenHeader] {
def renderInRequests = false
def renderInResponses = false
override val name = "Authorization"
override def parse(value: String) = Try(new ApiTokenHeader(value))
}
final class ApiTokenHeader(token: String) extends ModeledCustomHeader[ApiTokenHeader] {
def renderInRequests = false
def renderInResponses = false
override val companion = ApiTokenHeader
override def value: String = "Bearer " + token
}
and use it as
val responseFuture = pipeline {
Get("https://api.guildwars2.com/v2/commerce/listings/46741").withHeaders(ApiTokenHeader("55eec993e046c63bc8f486ee"))
}
I didn't compile it but it should work.

Playframework POST parameter

I'm trying to go something really simple with Playframework Scala (2.3): create a route POST and get POST parameters.
The route definition
POST /ff/user controllers.Application.createUser
The controller
def createUser = Action.async { request =>
val user = request.queryString.get("user").flatMap(_.headOption)
val email = request.queryString.get("email").flatMap(_.headOption)
val firstname = request.queryString.get("firstname").flatMap(_.headOption)
val lastname = request.queryString.get("lastname").flatMap(_.headOption)
Logger.debug("Create User")
Logger.debug(s"user=$user")
Logger.debug(s"email=$email")
Ok("Youpi")
}
When I post a request to /ff/user, the log says : user=None, email=None.
I cannot figure out why they are "None". What is wrong?
Thank for helping.
When using a POST like this, you probably want to look at the body field on the request parameter, which will contain the form that was posted. You usually don't use a query string with POST requests (more about that here). So, that might look like:
def createUser = Action.async { request =>
val user = request.body.asFormUrlEncoded.get.get("user").head
Future(Ok())
}
You might also want to use the Action.async overload that provides a parsed body. For example, it might look like:
def createUser = Action.async(parse.urlFormEncoded) { request =>
//body is already treated as a Map[String, Seq[String]] because of the parameter passed to async
val user = request.body("user").head
Future(Ok())
}

Scala play http filters: how to find the request body

I'm trying to write a filter similar to the simple one described in http://www.playframework.com/documentation/2.1.1/ScalaHttpFilters but I need to access the request body. The documentation below states that "when we invoke next, we get back an Iteratee. You could wrap this in an Enumeratee to do some transformations if you wished." I'm trying to figure out how to wrap the Iteratee so I can get the request body as a string within the filter so I can log that as well.
First thing you have to know is when the Filter is invoked, the request body is not parsed yet. That's why it's giving you a RequestHeader. You'll have to find out the type of body, and call the proper body parser accordingly.
You can find a example of body parsing in the CSRF filter (It can lookup for CSRF tokens in the first bytes of the request body).
See: https://github.com/playframework/playframework/blob/master/framework/src/play-filters-helpers/src/main/scala/csrf.scala#L221-L233.
Hope it helps.
I spent some time on this.
I am no means a Scala expert but this works pretty well! :)
object AccessLog extends EssentialFilter {
def apply(nextFilter: EssentialAction) = new EssentialAction {
def apply(requestHeader: RequestHeader) = {
val startTime = System.currentTimeMillis
nextFilter(requestHeader).map { result =>
val endTime = System.currentTimeMillis
val requestTime = endTime - startTime
val bytesToString: Enumeratee[ Array[Byte], String ] = Enumeratee.map[Array[Byte]]{ bytes => new String(bytes) }
val consume: Iteratee[String,String] = Iteratee.consume[String]()
val resultBody : Future[String] = result.body |>>> bytesToString &>> consume
resultBody.map {
body =>
Logger.info(s"${requestHeader.method} ${requestHeader.uri}" +
s" took ${requestTime}ms and returned ${result.header.status}")
val jsonBody = Json.parse(body)
Logger.debug(s"Response\nHeader:\n${result.header.headers.toString}\nBody:\n${Json.prettyPrint(jsonBody)}")
}
result.withHeaders("Request-Time" -> requestTime.toString)
}
}
}
The end result will print the body as a Json String (pretty printed).
In the controller method that routes to the action, simply call
Map<String, String[]> params = request().queryString();
This will get you a map of parameters, where you can then call
params.get("someParam")[0]
to get the param (if it is a single value). If the param is a list, ignore the indexing andthat will return an array.

HTTP Post with scala and Dispatch?

I want to write a function for uploading photos to flickr as http://www.flickr.com/services/api/upload.api.html. I wrote the following code:
val http = new Http with thread.Safety
val uploadEndPoint = :/("api.flickr.com") / "services" / "upload"
then I sign the method using dispatch
def signUploadRequest(userParams: Map[String, String], accessToken: Token, verifier: String): Map[String, String] = {
var map = userParams
map += "api_key" -> consumerKey
sign("", uploadEndPoint.toString, userParams, consumer, Some(accessToken), Some(verifier), Some(OAuth.oob))
}
Then I call the following method:
def sendUploadRequest(reqParms: Map[String, String]) = {
http(uploadEndPoint.POST <:< reqParms as_str)
}
but I got the following error:
<rsp stat="fail">
<err code="100" msg="Invalid API Key (Key has invalid format)" />
</rsp>
I use the same procedure for requests and it works fine. What is the problem with the Post?
Thanks,
Feras
I don't know this flickr api, but shouldn't the map pass as the request body ?
Another remark is that, they say that the photo can't be part of the signature (just in case the userParams contains its).
So, if you should use post's body instead of putting the map in the headers (which does <:<):
def sendUploadRequest(reqParms: Map[String, String]) = { http(uploadEndPoint << reqParms as_str) }
The << convert the request to post, using the given map as the payload. Note that using POST will set the Map body as empty.