What is the relationship between filters and modules? [Scala/2.5.x]

66 views
Skip to first unread message

Jeff White

unread,
Feb 19, 2017, 6:12:35 PM2/19/17
to Play Framework
The documentation for creating a Filter doesn't mention needing to create an associated Module, however when I look at the implementation of all the built-in Filters (gzip etc), I see corresponding Modules. What are the circumstances in creating a Filter that I would want to create an associated Module?

My goal is to create some reusable Filters for use in both compile-time DI and runtime DI apps.

jeff

Greg Methvin

unread,
Feb 19, 2017, 7:41:46 PM2/19/17
to play-framework
Hi Jeff,

The Filter API itself doesn't have any requirements with respect to DI bindings. You just need to somehow create the filter, e.g. return it from a HttpFilters instance or override the filters in BuiltInComponents. But if your filter is going to be used in multiple places, it's usually a good idea to declare bindings in one place for convenience.

All of the Play-provided filters provide both a components trait for compile-time DI and a module (play.api.inject.Module) for runtime DI. The components trait usually defines abstract methods for anything in BuiltInComponents, so it can be easily mixed into the cake and just work. The Module does the same for runtime DI by declaring any needed bindings and providers, e.g. to parse configuration.

In some cases, like the CSRF filter, this saves a lot of work wiring together dependencies: https://github.com/playframework/playframework/blob/master/framework/src/play-filters-helpers/src/main/scala/play/filters/csrf/csrf.scala#L281. Depending on your needs you don't have to do something as sophisticated as parsing out all those config options, but either way it is helpful to have the module or trait available to install so everything just works in a reasonable default configuration.

Since it seems like you want your filter to work well in all kinds of Play apps, I'd suggest providing both a module and a components trait.

Cheers,
Greg

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/1613b184-9f4f-4c3f-b6ba-3ecf3b1c12f7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Greg Methvin
Tech Lead - Play Framework

Jeff White

unread,
Feb 23, 2017, 9:42:41 PM2/23/17
to Play Framework
Hi Greg,

Thanks for the very informative reply. I followed the model of SecurityHeadersFilter in creating my filter. I have a couple questions:

1) SecurityHeadersConfig makes use of PlayConfig which is private[play]. So I am using Configuration.underlying to access the config. I'm not sure if that is the recommended approach.

2) Per this thread, my filter constructor has an implicit Materializer parameter, which I needed to wire in via the following snippets, including defining a dependency in the components trait. Is that the recommended approach?

object AccessLogFilter {
 
def apply(config: AccessLogConfig = AccessLogConfig())(implicit mat: Materializer): AccessLogFilter = new AccessLogFilter(config)
 
def apply(config: Configuration)(implicit mat: Materializer): AccessLogFilter = new AccessLogFilter(AccessLogConfig.fromConfiguration(config))
}

class
AccessLogFilter @Inject() (config: AccessLogConfig)(implicit val mat: Materializer) extends Filter {...}

trait AccessLogComponents {
 
def configuration: Configuration
 
implicit def materializer: Materializer
 
lazy val accessLogConfig: AccessLogConfig = AccessLogConfig.fromConfiguration(configuration)
 
lazy val accessLogFilter: AccessLogFilter = AccessLogFilter(accessLogConfig)
}





On Sunday, February 19, 2017 at 4:41:46 PM UTC-8, Greg Methvin wrote:
Hi Jeff,

The Filter API itself doesn't have any requirements with respect to DI bindings. You just need to somehow create the filter, e.g. return it from a HttpFilters instance or override the filters in BuiltInComponents. But if your filter is going to be used in multiple places, it's usually a good idea to declare bindings in one place for convenience.

All of the Play-provided filters provide both a components trait for compile-time DI and a module (play.api.inject.Module) for runtime DI. The components trait usually defines abstract methods for anything in BuiltInComponents, so it can be easily mixed into the cake and just work. The Module does the same for runtime DI by declaring any needed bindings and providers, e.g. to parse configuration.

In some cases, like the CSRF filter, this saves a lot of work wiring together dependencies: https://github.com/playframework/playframework/blob/master/framework/src/play-filters-helpers/src/main/scala/play/filters/csrf/csrf.scala#L281. Depending on your needs you don't have to do something as sophisticated as parsing out all those config options, but either way it is helpful to have the module or trait available to install so everything just works in a reasonable default configuration.

Since it seems like you want your filter to work well in all kinds of Play apps, I'd suggest providing both a module and a components trait.

Cheers,
Greg
On Sun, Feb 19, 2017 at 3:12 PM, Jeff White <jsw...@ebay.com> wrote:
The documentation for creating a Filter doesn't mention needing to create an associated Module, however when I look at the implementation of all the built-in Filters (gzip etc), I see corresponding Modules. What are the circumstances in creating a Filter that I would want to create an associated Module?

My goal is to create some reusable Filters for use in both compile-time DI and runtime DI apps.

jeff

--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages