RFC: lightweight service container
Problem
There are a number of cross-cutting concerns which cannot easily be componentised using the current component system since they need to be used by other components without being referred to by name. So far we have:
-
email
- provides a way for components to send email without caring about the underlying delivery mechanism -
auth
- components need to check authorisation without knowing which authsome mode is being used -
logger
- components need to log stuff without knowing where it is going -
file storage
- components need to write and read file data without knowing where it is stored
Current solutions
Currently we are using a mixture of patterns to achieve this:
-
email
andauth
- implement the service in a module and put a reference to the module in the app config. This leads to odd-looking code likeconst mode = require(config.get('authsome.mode'))
. It's also not clear in the config which values are actually module references. -
logger
- store the actual service in the config but create a dedicated package for it and expose a method which allows application code to replace this value at runtime and have this change affect all consumers of the service. The first part (non-serialisable objects in config) leads to problems with node-config and the second part (dedicated package per service) is a lot of repeated code. -
file storage
- doesn't exist yet
Proposed solution
Create a small wrapper to standardise the way we do this.
Add a section in the config:
"services": {
"server": {
"email": "@pubsweet/aws-ses-mailer",
"auth": "./src/auth/mode.js",
"logger": "winston",
...
},
"client": {
"auth": "./src/auth/mode.js"
}
},
Then consume a service like:
const services = require('pubsweet-server/src/services')
const mailer = services('email')
or
const services = require('pubsweet-client/src/services')
const authsome = services('auth')