When you write a software you generally split it into several modules with no hardcoded dependencies between them so you can reuse and test them more easily: you just need to wire the different modules together at startup according to your desired configuration.
In the Java world, some tools help to perform the wiring task, e.g. Spring or Guice, but in Scala you can perform dependency injection without having to rely on an external tool, as you’ll see in this post where I’ll show how to apply the Cake pattern in the context of a Play 2 application.
An example of use case where you may want to use a dependency injection mechanism is when you write a web application which needs the user to be authenticated to perform some actions. During development time it’s generally more comfortable to bypass the authentication step (when you just want to quickly test features you are coding right now). Thus, you want to have two authentication strategies: one for the integration environment, which really asks the user its login and password, and one always succeeding without requiring any user action.
Well, how can we define an authentication process in Play 2? A simple solution is defined with the following code:
It defines a main controller with two interesting actions: login
and logout
. The former reads a username from the request and put it in the session while the latter clears the session. Thus, checking if a user is not a guest is just a matter of checking if there is a username in his session. Then I defined the Secured
object, which provides a function executing a given action only if there is a username in the session (otherwise it renders the unauthorized
template and returns an Unauthorized
status code).
Given this code we can easily rewrite the index
action to ensure the user is authenticated: we just wrap the Action
statement into a Secured.Authenticated
statement.
Well, we have a basic authentication mechanism and a convenient Authenticated
construct we can use to wrap actions for which we want the user to be authenticated. Now, as previously written, we also want a mocked Authenticated
construct variant which checks nothing. Its definition is straightforward:
With all that given code we can either wrap our authenticated actions with the Secured.Authenticated
function, or with the MockSecured.Authenticated
function to either use the “real” or the mock authentication check, but by doing this we’d hardcode the authentication strategy and that’s definitely not what we want to do.
Thus, we want to abstract over the authentication strategy, e.g. with a Security
trait implemented by Secured
and MockSecured
.
Then, we need to express that MyApp
controller depends on the Security
trait. To do that we will change the MyApp
object into a trait and add the Security
trait to its selftype:
Now we are almost done! The index
action will use the Security.Authenticate
function that will be injected in the MyApp
controller. So, the only remaining task is to define the injection logic.
Java based dependency injection frameworks use either XML configuration files or @Annotations to define the wirings. In Scala, you write the wirings in Scala. The good thing is that it is type-checked so the program will not compile if a dependency is missing (whereas you’d get a runtime NullPointerException
with Spring, for example).
Here is a simple wiring code which will use the MockedSecured
strategy if Play is in dev mode, and the Secured
strategy in prod mode:
And we are done! You can find a working example on GitHub. Use the run
command (in the play prompt) to run the application in dev mode (with mocked authentication) and the start
command to run in prod mode (with the real authentication).