components-container
Easy and clean way to manage async and sync components in simple and complex projects.
Getting Started
Installing
In your project run
$ npm install @soluzioni-futura/components-container
The design pattern
The components-container
design pattern is inspired from PHP Slim's Dependecy Container.
You have a higher order container that handles multiple components and manage to grant
communication between them.
You can consider a component
every configured SDK, client or abstraction that allows your project to use a service or to accomplish certain operations.
Usage
const Container = require("components-container")
const mysqlComponent = require("./components/mysqlComponent.js")
const productsComponent = require("./components/productsComponent.js")
const container = new Container({
debugTag: "container", // override of the default debug tag; default "container"
noColors: true // enable the console colors of the debug logs; default true
})
container
.register(mysqlComponent)
.register(productsComponent)
.init()
Component definition
module.exports = {
/*
the name property is required and represents the component handler
*/
name: "component-name",
/*
the init async function is required and must return whatever you
need to retrieve with the container get function
*/
init: async ({ setStatus, getStatus, container }) => {
// ...
return client
},
/*
the checkStatusInterval property is optional and is expressed in milliseconds
*/
checkStatusInterval: 5000,
/*
the checkStatus function is optional and will be called every checkStatusInterval
*/
checkStatus: async ({ component, setStatus }) => {
// ...
setStatus(STATUS.STOPPED, new Error("connection lost"))
},
/*
the debugTag property overrides the default debugTag property; defaults to component name
*/
debugTag: "debug-log-tag-name",
}
Events
components-container
emits various events to fully control and customize how your application must react to status changes.
Every status change inside a component will emit an event <component-name>.<new-status>
.
You can easily subscribe to these changes:
container.on("products.running", async () => {
// ...
}
Components retrieval
You can use the Container
instance to easily retrieve init function return value of each component.
const mysqlClient = await container.get("mysql-component")
Example
Fake mysql component
mysql-component.js
const { STATUS } = require("components-container")
/*
this is the mysql component definition:
there are 2 required fields:
- name
- init
and 4 optional:
- checkStatusInterval
- checkStatus
- debugTag
*/
module.exports = {
/*
the name property is required and represents the component handler
*/
name: "mysql",
/*
the init async function is required and must return whatever you
need to retrieve with the container get function
*/
init: async ({ setStatus, getStatus, options }) => {
// this is a fake mysql client
const mysqlFakeClient = {
options,
// the query function fakes a mysql query and returns a fake product object
query: fakeSql => {
if (getStatus().status !== STATUS.RUNNING) {
throw new Error("Can't execute query, not connected to database")
} else {
console.log("Faking query execution:", fakeSql)
return {
product: {
id: 123,
name: "pizza",
price: 10
}
}
}
},
// the connect function fakes the connection to the database
connect: () => {
console.log("Connecting to database...")
setTimeout(() => {
if (getStatus().status !== STATUS.RUNNING) {
console.log("Connection established")
setStatus(STATUS.RUNNING)
}
}, 500)
}
}
mysqlFakeClient.connect()
return mysqlFakeClient
},
/*
the checkStatus function is optional and will be called every checkStatusInterval
*/
checkStatus: async ({ component, setStatus }) => {
/*
random switch of the component status from RUNNING to STOPPED
and vice versa to fake ane intermittent connection
*/
if (Math.random() > 0.5) {
component.connect()
} else {
setStatus(STATUS.STOPPED, new Error("connection lost"))
}
},
/*
the checkStatusInterval property is optional and is expressed in milliseconds
*/
checkStatusInterval: 5000,
/*
the debugTag property overrides the default debugTag property; defaults to component name
*/
debugTag: "debug-log-tag-name",
}
index.js
const Container = require("components-container")
const container = new Container({
debugTag: "container", // override of the default debug tag; default "container"
noColors: true // enable the console colors of the debug logs; default true
})
container
.register(require("./components/mysql.js"), { host: "example.com" })
.register(require("./components/products.js"))
.init()
Development
Running the tests
You can run tests running:
$ npm run test
Authors
- Giovanni Bruno - giowe
- Nicolò Fuccella - nicofuccella
See also the list of contributors who participated in this project.
License
This project is licensed under the MIT License - see the LICENSE file for details