Watson provides an easy to use IoC (Inversion of Control) container which allows these sorts of dependencies to be managed easily. Lets take a look at how we might instantiate a database connection without dependency injection (for a more complete example of this, check out watson-db)

One thing to note here is that the configuration for the collection is stored within the code itself. While we could abstract this out to another module, there would still be some sort of dependency on retrieving the configuration from that module. We also introduce a hardcoded dependency by requiring the db module. By using the IocContainer, we can abstract both of these issues out keeping our codebase clean.

We now have two dependencies defined in the applications configuration settings. One of the additional benefits of using the IoC container is that subsequent requests for a dependency will return an already instantiated instance of the dependency (unless otherwise specified).

Now all that’s left is to retrieve the dependency from the container. We can do this by calling container.get(dependency_name). As controllers are retrieved from the container and extend ContainerAware, our container is automatically injected into them.

app_name/controllers/user.py

fromwatson.frameworkimportcontrollersclassProfile(controllers.Rest):defGET(self):# we only want to read from a slave for some reasondb=self.get('db_read')return{'users':db.query(User).all()}defPOST(self):# we only want writes to go to a specific databasedb=self.get('db_write')user=User(name='user1')db.add(user)db.commit()

We can also take this a step further and remove the container itself so that we’re not utilizing it as a service locator (db = self.get(‘db_*’)). We do this by adding the controller itself to the dependency definitions, and injecting the dependency either as a property, setter, or through the constructor. We can get access to the container itself (for retrieving dependencies or configurtion) via lambdas, or just by the same name as the definition. Note that you can also omit the ‘item’ key if you are configuring a controller.

Params are arguments that can be inserted into dependencies via init, property or setter processors. Any argument that is being used in one of the above processor definitions will be evaluated against the params and replaced with it’s value. If a param value has the same name as a dependency, then that dependency itself will be injected.