[akka-http] Custom Directives - Scala

657 views
Skip to first unread message

tdroz...@gmail.com

unread,
Aug 25, 2015, 2:23:54 AM8/25/15
to Akka User List
I'm new to working with akka-http and have a question that I hope someone can provide some guidance with.

I've been trying to build my own custom directive - that would take the results of an existing directive - perform some logic and then move onto the next directive, or reject route. 

For example...

Let's say I want to take the extractClientIp directive, use the RemoteAddress value to perform some logic and either continue on with further directives or reject the request.  I don't intend to complete the request here.

Is this possible?  To make this re-usable is a directive what I'd want to do here?  Or am I over thinking this?

Any help is appreciated!

-t

Tomasz Kogut

unread,
Aug 26, 2015, 10:24:01 AM8/26/15
to Akka User List
A directive is basically a function:

type Route = RequestContext ⇒ Future[RouteResult]

val route: Route = { (ctx: RequestContext) => 
ctx.complete("yeah")
}


so just see what you have available in the `ctx` object. You can call ctx.reject when you don't want to pass it further.

If your directive needs to take parameters just change val to def and add whatever you need.

Best way to learn different neat things is to look at already created directives.

tdroz...@gmail.com

unread,
Aug 27, 2015, 1:23:00 AM8/27/15
to Akka User List
Tomas,

Thanks for the response.

So I get how to do a basic custom directive.  Where I'm having difficulty is if I try to reference another directive within my custom directive.

Here's what I'm trying to do:


Here's the compile error I receive:

Error:(74, 22) type mismatch;
 found   : akka.http.scaladsl.server.Directive1[java.net.InetAddress]
    (which expands to)  akka.http.scaladsl.server.Directive[(java.net.InetAddress,)]
 required: akka.http.scaladsl.server.StandardRoute
              provide(address)
                     ^

To me it appears that the reject properly resolves as a Directive.  But I'm not ready to complete the route here - this requires an inner route to do something with the provided address.

I think perhaps I'm missing something in regards to how Directives compose.  I've been reviewing all the existing routes, and it looks like this should work - but its not.

-t

Tomasz Kogut

unread,
Aug 27, 2015, 9:47:02 AM8/27/15
to Akka User List
You are trying to create route at one place (reject part) and directive in another (provide).

Directives can pass and reject stuff eventually they will produce a Route.

Maybe this is more or less you want to achive? Notice the predicate part added. This will be a simple function composition now.

As for using directives to reject stuff:

in source you can find sth like this:

private val _rejectEmptyResponse: Directive0 =
mapRouteResult {
case Complete(response) if response.entity.isKnownEmpty ⇒ Rejected(Nil)
case x ⇒ x
}

this basically shows how to change already created routest.

Johannes Rudolph

unread,
Aug 28, 2015, 1:28:06 AM8/28/15
to Akka User List
Hi,

use the combinators of the Directive class to make custom directives. E.g.

extractClientIp.flatMap { ip =>
  val cond = // something
  if (cond) pass else reject(...)
}

or if you want to return a value, i.e. create a Directive1[T], use `provide` instead of `pass`.

HTH
Johannes

tdroz...@gmail.com

unread,
Aug 30, 2015, 5:09:38 PM8/30/15
to Akka User List
Thanks Tomasz - this helps me understand a lot.  Exactly what I need!
Reply all
Reply to author
Forward
0 new messages