Dependency Modules
By using Brandi, you can organize bindings in dependency modules. In this section we will see how to create, organize and use your modules.
DependencyModule
is a logical space to help you organize your bindings.
It is similar to Container
, but it can only store dependencies, but not resolve or inject them.
DependencyModule
Methods
DependencyModule
repeats the following Container
methods:
Using Dependency Modules
Simple Example
Let's take an simple example, with using a binding from a module by the token:
import { Container, DependencyModule, token } from 'brandi';
const TOKENS = {
apiKey: token<string>('apiKey'),
};
const apiModule = new DependencyModule();
apiModule.bind(TOKENS.apiKey).toConstant('#key9428');
const container = new Container();
container.use(TOKENS.apiKey).from(apiModule);
const key = container.get(TOKENS.apiKey);
expect(key).toBe('#key9428');
Container will resolve the apiKey
dependency from the module.
More Complex Example
In this example, we have the ApiService
that depends on a apiKey
, API dependency module, and the App
that depends on an ApiService
.
Let's start with the token declaration:
import { token } from 'brandi';
import type { ApiService } from './api/ApiService';
import type { App } from './App';
export const TOKENS = {
apiKey: token<string>('apiKey'),
apiService: token<ApiService>('apiService'),
app: token<App>('app'),
};
Then we will create the ApiService
with a dependency on a apiKey
:
import { injected } from 'brandi';
import { TOKENS } from '../tokens';
export class ApiService {
constructor(private apiKey: string) {}
/* ... */
}
injected(ApiService, TOKENS.apiKey);
Then we will create the dependency module to which we will bind all the dependencies necessary for the API module:
import { DependencyModule } from 'brandi';
import { TOKENS } from '../tokens';
import { ApiService } from './ApiService';
export const apiModule = new DependencyModule();
apiModule.bind(TOKENS.apiKey).toConstant('#key9428');
apiModule.bind(TOKENS.apiService).toInstance(ApiService).inTransientScope();
Creating our App
that depends on ApiService
:
import { injected } from 'brandi';
import { TOKENS } from './tokens';
import type { ApiService } from './api/ApiService';
export class App {
constructor(private apiService: ApiService) {}
/* ... */
}
injected(App, TOKENS.apiService);
And finally configure the container:
import { Container } from 'brandi';
import { TOKENS } from './tokens';
import { apiModule } from './api/module';
import { App } from './App';
export const container = new Container();
/**
* ↓ We only use the `apiService` token that the `App` directly depends on.
* The `apiKey` token binding will be resolved from the `apiModule` automatically
* and it does not need to be bound additionally.
*/
container.use(TOKENS.apiService).from(apiModule);
container.bind(TOKENS.app).toInstance(App).inSingletonScope();
Let's run:
import { TOKENS } from './tokens';
import { container } from './container';
const app = container.get(TOKENS.app);
app.run();
Some of your dependency modules may use bindings from other modules. If there are bindings of the same token in the module chain, the highest-level binding in the hierarchy will be used.
createDependencyModule()
createDependencyModule()
— is alias for new DependencyModule()
.