Scaldi is an elegant DI library in Scala.
Scaldi provides simple and elegant way to do dependency injection in Scala. By using expressive power of the Scala language it defines intuitive and idiomatic DSL for binding and injecting dependencies.
Since Skinny Framework 1.1.5, you can use it seamlessly with Skinny apps. This article shows you a small but pragmatic example.
If you'd like to know about Scaldi integration in detail, visit the official docmentation:
http://skinny-framework.org/documentation/dependency-injection.html
This is an important notice. Unfortunately, Scaldi doesn't work fine in Scala 2.10.x due to SI-6240. Use Scala 2.11.
Let's get the latest skinny-blank-app-with-deps.zip from the official website.
http://skinny-framework.org/#try-it-right-now
unzip skinny-blank-app-with-deps.zip
cd skinny-blank-app
./skinny run
Access localhost:8080 from your browser. Now your first Skinny app works!
Skinny's Scaldi integration adaptor is an optional library. Add the following to libraryDependencies.
"org.skinny-framework" %% "skinny-scaldi" % skinnyVersion,
"com.github.seratch" %% "awscala" % "0.2.+",
The example in this article also uses AWScala which is a simple wrapper of AWS Java SDK.
https://github.com/seratch/AWScala
Before trying this example, set AWS credentials.
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_KEY=yyy
First, you need to do the following things.
- Create a trait as an interface and the default implementation class (or just a class is also fine)
- Create a class which extends scaldi.Module trait
- Add module definitions to application.conf
- Use injected components in controllers
package model
import awscala.s3._
trait AWSClient {
def s3Buckets: Seq[Bucket]
}
package model
import awscala._, s3._
class AWSClientImpl extends AWSClient {
implicit val s3 = S3()
override def s3Buckets: Seq[awscala.s3.Bucket] = s3.buckets
}
package module
import model._
// must be a class
class AppModule extends scaldi.Module {
bind[AWSClient] to new AWSClientImpl
}
development {
scaldi {
modules: ["module.AppModule"]
}
}
package controller
import skinny._
import skinny.filter._
import skinny.controller.feature.ScaldiFeature
trait ApplicationController extends SkinnyController
with ScaldiFeature // <- Added!
with ErrorPageFilter {
}
package controller
import skinny._
import model._
class RootController extends ApplicationController {
def index = {
set("buckets" -> inject[AWSClient].s3Buckets)
render("/root/index")
}
}
<%@val buckets: Seq[awscala.s3.Bucket] = Nil %>
<%import skinny.util.JSONStringOps._ %>
<h3>Hello World!</h3>
<hr/>
<p>
Your first Skinny app works!
</p>
#for (bucket <- buckets)
<p>${toJSONString(bucket)}</p>
#end
Your S3 buckets should be shown at localhost:8080.
To replace components when running tests, you need to prepare additional ones as follows.
- Create a Scaldi module for testing
- Cteate a mock implementation and bind it to the Scaldi module
- Add the module to application.conf in test env
Be aware that this class is placed under “src/test/scala”.
package model
import awscala._, s3._
class AWSClientMockImpl extends AWSClient {
override def s3Buckets: Seq[Bucket] = Seq(Bucket("foo"), Bucket("bar"))
}
Be aware that this class is placed under “src/test/scala”.
package module
import model._
// must be a class
class TestModule extends scaldi.Module {
bind[AWSClient] to new AWSClientMockImpl
}
Add Scaldi modules to test env settings.
development {
scaldi {
modules: ["module.AppModule"]
}
}
test {
scaldi {
modules: ["module.TestModule"]
}
}
OK, let's run ./skinny test
.
You don't need real AWS configuration and payment for each test execution anymore :-)
Of course, Scala is a so powerful language that you can inject dependencies without libraries (just create a trait and override some APIs).
However, using Scaldi looks so easy-to-use and elegant. If you're familiar with dependency injection pattern (especially in Java), try it out with Skinny Framework.
The example in the article is here:
https://github.com/skinny-framework/skinny-scaldi-example
Enjoy!