Skip to content

Instantly share code, notes, and snippets.

@pulse00
Last active November 4, 2021 10:19
Show Gist options
  • Save pulse00/9066731 to your computer and use it in GitHub Desktop.
Save pulse00/9066731 to your computer and use it in GitHub Desktop.
spray-client http post request with custom header and json4s unmarshalling/marshalling
package com.example.actors.github
import spray.httpx.Json4sSupport
import org.json4s.{DefaultFormats, Formats}
/**
* Marshalling/Unmarshalling for the github json format
*
* see http://developer.github.com/v3/oauth/#web-application-flow
*/
object GithubJsonProtocol extends Json4sSupport {
override implicit def json4sFormats: Formats = DefaultFormats
case class TokenRequest(client_id: String, client_secret: String, code: String, redirect_uri: String)
case class GithubApiResult(access_token: String, scope: String, token_type: String)
}
package com.example.actors.github
import akka.actor.{ActorLogging, ActorRef, Actor}
import scala.util.{Failure, Success}
import spray.client.pipelining._
import scala.concurrent.Future
import spray.http.{HttpResponse, HttpRequest}
import com.dubture.actors.github.OAuthActor.{TokenRetrieved, ExchangeToken}
// marshaller/unmarshaller implicits for the pipeline
import GithubJsonProtocol._
/**
* Companion object defines messages retrieved/sent by this actor.
*/
object OAuthActor {
case class ExchangeToken(code: String)
case class TokenRetrieved(token: String)
}
/**
* Retrieve an oauth token from the github API v3
*
* @param clientId
* @param clientSecret
* @param redirectUri
*/
class OAuthActor(clientId: String, clientSecret: String, redirectUri: String) extends Actor with ActorLogging {
val accessTokenUri = "https://github.com/login/oauth/access_token"
/**
* Fire an HTTP POST request to the github API to exchange an oauth code against a persistent token
*
* @param requestor
* @param code
*/
def retrieveTokenFromCode(requestor: ActorRef, code: String) = {
// execution context for the future
import context.dispatcher
// setup request/response logging
val logRequest: HttpRequest => HttpRequest = { r => log.debug(r.toString); r }
val logResponse: HttpResponse => HttpResponse = { r => log.debug(r.toString); r }
val pipeline = (
// we want to get json
addHeader("Accept", "application/json")
~> logRequest
// if this shows a compilation error in IntelliJ, it is just a bug in the IDE - it compiles fine
~> sendReceive
~> logResponse
~> unmarshal[GithubApiResult]
)
// get the future
val response: Future[GithubApiResult] = pipeline { Post(accessTokenUri, TokenRequest(clientId, clientSecret, code, redirectUri)) }
// handle result/failure
response.onComplete {
case Success(response: GithubApiResult) => requestor ! TokenRetrieved(response.access_token)
case Failure(e) => requestor ! Failure(e)
}
}
override def receive = {
case ExchangeToken(code) => retrieveTokenFromCode(sender, code)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment