Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tsantos84/service-bucket-js
Service container for NodeJS + Typescript
https://github.com/tsantos84/service-bucket-js
dependency-injection nodejs typescript
Last synced: 19 days ago
JSON representation
Service container for NodeJS + Typescript
- Host: GitHub
- URL: https://github.com/tsantos84/service-bucket-js
- Owner: tsantos84
- License: mit
- Created: 2019-08-07T21:08:31.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2022-12-30T18:23:00.000Z (about 2 years ago)
- Last Synced: 2024-12-18T00:51:57.011Z (24 days ago)
- Topics: dependency-injection, nodejs, typescript
- Language: TypeScript
- Size: 409 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# PoC - Service Container for Typescript
This is a Proof of Concept to validate an alternative to Inversify package.
## Concept
Service container is a object that resolves and retrieve all services used by an application.
## Use cases
### Simplest use case
Register a `Logger` service in container and retrieve the concrete service after compile the container.
```typescript
const container = new ContainerBuider();
container.register(Logger); // returns a new service definition
container.compile();
const logger:Logger = container.get('Logger');
console.log(logger === container.get('Logger')); // true
```All services are shared by default, it means that consequent calls to container for the same service will return the same instance always.
### Non shared services
```typescript
const container = new ContainerBuider();
container.register(Logger).shared(false);
container.compile();
const logger:Logger = container.get('Logger');
console.log(logger === container.get('Logger')); // false
```### Defining parameters to container
Passing arguments to services through container parameters.
```typescript
container.parameters.set('project.env', process.env.NODE_ENV)
container.register(Logger).withArguments('%project.env%');
container.compile();
const logger:Logger = container.get('Logger');
```### Defining dependency betweeng services
Injecting constructor dependency as a reference
```typescript
container.register(Logger).withArguments(new Reference('ConsoleTransport'));
container.register(ConsoleTransport);
container.compile();
const logger:Logger = container.get('Logger');
```### Decorating the services
Decorates the service after its initialization. You can add one or more decorators
for the same service.```typescript
container.register(Logger).decorate((logger:Logger, container:Container) => {
logger.addTransport(container.get('ConsoleTransport'));
return logger; // required return
});
container.register(ConsoleTransport);
container.compile();
const logger:Logger = container.get('Logger');
```### Merging container builders
You can merge the service definitions. One container can define reference to a service
defined in another container before compilation.```typescript
const containerA = new ContainerBuilder();
const containerB = new ContainerBuilder();
containerA.merge(containerB);
containerA.compile();
const logger:Logger = container.get('Logger');
```### Organizing containers with extensions
Good way to organize the services in separated containers and merge them after its configuration is done.
Each extension will receive an empty `ContainerBuilder` on `configure` method and then merged to the main container.```typescript
const container = new ContainerBuilder();
container.registerExtension(new LoggerExtension());
container.registerExtension(new DatabaseExtension());
container.compile();
const logger:Logger = container.get('Logger');
```### Tagging services
You can tag the services to pass custom metadata to service definition. The example bellow passes an array of `TransportInterface` as a first parameter to service `Logger`. This technique is known as `multiInject` on `Inversify`
package.```typescript
const container = new ContainerBuilder();
container.register(ConsoleTransport).addTag('logger.transport');
container.register(RedisTransport).addTag('logger.transport');
// inject all services tagged with logger.transport as an array for the 1st argument
container.register(Logger).withArgument(0, '!tagged logger.transport');
container.compile();
const logger:Logger = container.get('Logger');
```### Auto registering the services
Instead of registering all services manually, you can pass a directory (glob pattern) and the container builder
will read all exported classes in the modules and register the definitions for them.```typescript
const container = new ContainerBuilder();container.registerResource('/path/to/logger/transports', {
tags: [
{name: 'logger.transport'}
]
})// inject all services tagged with logger.transport as an array for the 1st argument
container.register(Logger).withArguments('!tagged logger.transport');
container.compile();
const logger:Logger = container.get('Logger');
```### Factory Services
You can create a factory service and use it to create some service.
```typescript
const container = new ContainerBuilder();
container.register(MongoDatabase);
container
.register(MyCollection)
.factory('MongoDatabase', 'getCollection')
.withArguments('my_collection_name');
container.compile();
const collection = container.get>('MyCollection');
// TODO: needs work for async calls
```### Method calls
The container will automatically call the methods after the service is initialized.
```typescript
const container = new ContainerBuilder();
container
.register(MongoClient)
.addCall('connect', ['%mongo.url%']);
container.compile();
const logger:Logger = container.get('Logger');
// TODO: needs work for async calls
```## TODO:
* Async service factories
* Async method calls
* Autowiring
* Public vs private services
* Load from config file (yaml and json)
* Resolve environment variable
* Dump container to javascript module