@superhero/locator
v4.2.0
Published
Service locator to locate services by defined locator patterns
Downloads
724
Maintainers
Readme
Locator
A Node.js service locator module, designed to manage dependency injections for services, using an eager or lazy loading approach. This module simplifies service management by dynamically resolving and loading services and their dependencies, supporting wildcard service path maps and agile service resolution methods.
Features
- Eager Loading: Preload services in bulk for faster access, normally done at bootstrap by an application core process.
- Lazy Loading: Dynamically load services when they are required, and keep them accessible.
- Wildcard Service Paths: Resolve services using wildcard paths, to ease the service registry.
- Locator: Locate a service using different implementation alternatives.
- Destroy: Support for a graceful release of services resources.
- Error Handling: Provides detailed errors with specific error codes for different types of errors.
Installation
Install the module using npm:
npm install @superhero/locator
Usage
Importing the Locator
import locator from '@superhero/locator';
Lazyload a Service
const foobar1 = await locator.lazyload('foobar', './service.js');
const foobar2 = locator.locate('foobar');
// foobar1 === foobar2
Eagerload Services
await locator.eagerload({
serviceA: './services/serviceA.js',
serviceB: './services/serviceB.js',
});
const serviceA = locator.locate('serviceA');
const serviceB = locator('serviceB'); // optional interface to locate
Using a Wildcard Service Path
await locator.eagerload({ 'services/*': './services/*.js' });
const serviceA = locator.locate('services/serviceA');
const serviceB = locator.locate('services/serviceB');
Using Locators
Create custom locators to manage complex dependency trees.
Example: Exported locate
Function
export function locate(locator) {
return { foobar: locator.locate('foobar') };
}
Example: Locator Class
export class Locator {
locate(locator) {
return { foobar: locator.locate('foobar') };
}
}
Example: Static Class locate
Function
export default class Foo {
constructor(foobar) {
this.foobar = foobar;
}
static locate(locator) {
return new Foo(locator.locate('foobar'));
}
}
Destroy
Services can include a destroy
method to clean up resources during shutdown or unloading. The locator will automatically call the destroy
method for all services when the destroy
method is invoked on the service locator.
Example: Using Destroy
Define a service with a destroy
method:
export default new class {
destroy() {
console.log('Service is being destroyed.');
}
}
Destroy all loaded services:
await locator.eagerload({
serviceA: './services/serviceA.js',
serviceB: './services/serviceB.js',
});
await locator.destroy();
Error Handling During Destroy
If a service's destroy
method throws an error, the locator will aggregate these errors and throw a comprehensive error with details.
Example:
try {
await locator.destroy();
} catch (error) {
console.error(error.code); // 'E_LOCATOR_DESTROY'
console.error(error.cause); // Array of errors for each service taht failed to destroy
}
Error Codes:
- E_LOCATOR_DESTROY: Thrown when one or more destroy methods fail.
- E_LOCATOR_DESTROY_SERVICE: Thrown for individual service that fail to destroy.
Error Handling
The module provides descriptive errors with unique codes to help debug common issues.
- E_LOCATOR_LOCATE: Thrown when trying to locate a non-existent service.
- E_LOCATOR_LAZYLOAD: Thrown when lazy loading a service fails.
- E_LOCATOR_EAGERLOAD: Thrown when eager loading fails.
- E_LOCATOR_INVALID_SERVICE_MAP: Thrown for invalid service map formats.
- E_LOCATOR_SERVICE_UNRESOLVABLE: Thrown when a service path cannot be resolved.
- E_LOCATOR_INVALID_PATH: Thrown for invalid or mismatched wildcard paths.
- E_LOCATOR_DESTROY: Thrown when one or more
destroy
methods fail. - E_LOCATOR_DESTROY_SERVICE: Thrown for individual service
destroy
methods that fail.
Example:
try {
locator.locate('nonexistent/service');
} catch (error) {
console.error(error.code, error.message);
}
Running Tests
The module includes a test suite. Run the tests using:
node test
Test Coverage
▶ @superhero/locator
▶ Lazyload
✔ Lazyload a service (4.828123ms)
✔ Lazyload same service multiple times (2.175617ms)
✔ Lazyload (7.965349ms)
▶ Eagerload
✔ Eagerload a service (2.271103ms)
✔ Eagerload the same service multiple times (0.933762ms)
✔ Eagerload multiple services by a collection definition (2.389402ms)
✔ Multiple services by a service path map (1.368324ms)
✔ Nested wildcard service (6.644221ms)
✔ Specific file by a wildcard service path map (2.014441ms)
▶ Using a locator
✔ Locator file (3.275955ms)
✔ Exported locate function (2.851036ms)
✔ Exported locator class (4.530722ms)
✔ Static self locator (2.690786ms)
✔ When the dependent service is loaded after the located service (1.780561ms)
✔ Using a locator (15.620721ms)
✔ Eagerload (32.099219ms)
▶ Rejects
✔ Lazyload a nonexistent path (2.06964ms)
✔ Lazyload a nonexistent path (1.023868ms)
✔ Directory path with no index or locator file (1.619045ms)
✔ Invalid wildcard path (0.7834ms)
✔ File path is used as a directory path (0.638767ms)
✔ Missmatched wildcard count (0.423624ms)
✔ Invalid service map types (0.973865ms)
✔ Noneexisting path (3.930104ms)
✔ Invalid wildcard path (2.209812ms)
✔ Throws error for attempting to locate a nonexisting service (0.415812ms)
✔ Rejects (14.858727ms)
▶ Destroy
✔ Successfully destroys a service (2.558189ms)
✔ Throws if fails to destroy a service (2.610999ms)
✔ Destroy (5.839146ms)
✔ Locate using the locator method (0.889694ms)
✔ @superhero/locator (90.014072ms)
tests 26
suites 6
pass 26
----------------------------------------------------------------------------------------------------
file | line % | branch % | funcs % | uncovered lines
----------------------------------------------------------------------------------------------------
index.js | 94.42 | 94.34 | 76.67 | 25-27 47-50 331-333 459-463 477-480 494-499 515-518
index.test.js | 100.00 | 100.00 | 98.00 |
----------------------------------------------------------------------------------------------------
all files | 96.66 | 96.18 | 90.00 |
----------------------------------------------------------------------------------------------------
License
This project is licensed under the MIT License.
Contributing
Feel free to submit issues or pull requests for improvements or additional features.