Ian Phillips
Ian Phillips

Reputation: 567

How can I use a Future inside an Akka HTTP Directive?

I currently have a directive that I'm using to secure resources in an Akka HTTP app, like so:

def authenticate: Directive1[Login] =
  optionalHeaderValueByName("Authorization") flatMap {
    val accessToken = authz.split(' ').last
    case Some(authz) =>
      LoggedInUser findByAccessToken accessToken match {
        case Some(user) => provide(user)
        case None       => reject(AuthorizationFailedRejection)
      }
    case None => reject(AuthorizationFailedRejection)
  }

where LoggedInUser.findByAccessToken() makes a blocking query against a database, I would like to switch this for an asynchronous ask to an actor which which can provide the same data, I'm OK with passing in the ActorRef as a parameter to the directive but I cannot work out how to handle the Future that the ask returns.

None of the Directive1 examples that come with Akka HTTP seem to do this (at least I could;t find any) although there are examples of directives returning Route which do.

Is what I want to do even possible? Is a possible approach to create a StandardRoute subclass with a field for the user credentials and return that somehow?

Upvotes: 15

Views: 3857

Answers (1)

Nyavro
Nyavro

Reputation: 8866

Yes, it is possible. As far as I understand you need something like this:

def authenticate: Directive1[Login] = {
  def findByAccessToken(accessToken:String): Future[Option[Login]] = ???
  optionalHeaderValueByName("Authorization").flatMap {
    case Some(authz) =>
      val accessToken = authz.split(' ').last
      onSuccess(findByAccessToken(accessToken)).flatMap {
        case Some(user) => provide(user)
        case None       => reject(AuthorizationFailedRejection)
      }
    case None => reject(AuthorizationFailedRejection)
  }
}

Upvotes: 23

Related Questions