Node library exposing components with dependencies - javascript

I'm developing a Node.js ORM library based on Knex, similar to Bookshelf, for use in other personal projects.
Some components of my library require an initialised instance of Knex, so I wrapped them up in an object that gets a Knex instance in the constructor, using a wrapper function to insert the Knex object without having the user inserting it whenever using the library. I tried to do it similar to how Knex and Bookshelf do it, but I found that code hard to read, besides I use ES6 classes, so it's not quite the same.
This is my current code:
const _Entity = require('./Entity.js');
class ORM {
constructor(knex) {
// wrapper for exposed class with Knex dependency;
// knex is the first argument of Entity's constructor
this.Entity = function(...args) {
return new _Entity(knex, ...args);
};
// exposed class without Knex dependency
this.Field = require('./Field.js');
}
}
function init(knex) {
return new ORM(knex);
}
module.exports = init;
The idea is that the user can use it something like this:
const ORM = require('orm')(knex);
const Entity = ORM.Entity;
const Field = ORM.Field;
const User = new Entity('user', [
new Field.Id(),
new Field.Text('name'),
// define columns...
]);
let user = User.get({id: 5});
It bothers me that Entity is only indirectly exposed and the code looks odd to me. Is there any more elegant or a "standard" way to expose components with dependencies?

Just use a regular function? :
const _Entity = require('./Entity.js');
const Field = require('./Field.js');
module.exports = function init(knex){
return {
Field,
Entity: _Entity.bind(_Entity, knex)
};
};

Related

Dynamically construct list of all objects in package/directory

I have a directory containing all display types and I need to expose these types via an API. This set of display types will grow significantly over this application's lifecycle, so it'd be nice if adding a new type didn't require adding new code to our service layer.
So in a scenario where a subdir src/domain/types/ contains Type1.js, Type2.js, Type3.js, and Type4.js, is it possible to have a piece of code that instantiates all these types and adds those to some array? Something like:
// I know this line won't work, but you get the idea
const dir = require('../src/domain/types/')
getAllDisplayTypes() {
const types = []
for (const type in dir) {
// auto-magically create new type
types.push(someMagicallyCreatedType)
}
return types
}
where types would be an array where each entry is a set of default values created in the constructor of TypeX.js.
Alternatively, if you have a creative way to expose a set of domain object definitions, I'm all ears.
Figured it out. Using a package called require-dir that let's you require an entire directory, I was able to use some JS devilry to get this working:
const require_dir = require('require-dir')
const allTypes = require_dir('../domain/types/')
// ...
getDisplayTypes() {
const types = {}
for (const typeName of Object.keys(allTypes)) {
const typeConstructor = allTypes[typeName]
const typeInstance = new typeConstructor()
types[typeName] = typeInstance
}
return types
}

How to correctly make an entry point to my module, which is containing multiple classess?

I've started to develop a desktop app with node and electron. It has a package, which is implementing connection with some API. It is structured as one base class, and some derrived classes in this way:
ApiBase
ApiAuth extends ApiBase
ApiAuth.login()
ApiAuth.logout()
etc...
ApiTasks extends ApiBase
ApiTasks.getTaskList()
etc...
etc...
And now, i want to make nice and convinient way to use these classes in my app. So i need to create some entry point, which will provide an access to my API implementation. But, i do not have much expirience to make it right.
I thought about something like this:
index.js:
const ApiAuth = require('./amazing-time-api-auth');
const ApiTasks = require('./amazing-time-api-tasks');
apiAuth = new ApiAuth('www.sample-host.com');
apiTasks = new ApiTasks('www.sample-host.com');
module.exports = {
login: apiAuth.login,
logout: apiAuth.logout,
getTaskList: apiTasks.getTaskList,
etc...
}
somwhere at the app:
const api = require("./lib/someApi");
// need to get task list for some reason
api.getTaskList(param1, param2)
But there are some problems with this approach i managed:
it is a problem to pass host param to the constructors in index.js dynamicly
i am not sure if creating this instances everytime requiring index.js is a rigth thing
So i want to know about some approches i can use here, because i do now even know where to start research. Thank you.
I think that you identified some of the most crucial decisions with this:
it is a problem to pass host param to the constructors in index.js dynamicly
IMO Configuration and the interface are important considerations. Even though it can be refactored after the fact an easy to configure and consume interface will help reduce adoption of your library. As you pointed out the configuration is static right now and very brittle. Ie a change to the URL will cascade to all clients and require all clients to update.
A first intuitive alternative may be to allow dynamic configuration of the current structure:
apiAuth = new ApiAuth(process.env.API_AUTH_URL || 'www.sample-host.com');
apiTasks = new ApiTasks(process.env.API_TASKS_URL || 'www.sample-host.com');
While this allows client to dynamically configure the URL, the configuration is "implicit". IMO this is unintuitive and difficult to document. Also it's not explicit and requires a client to look in the code to see the environmental variables and instantiation flow.
I would favor exposing these classes to the client directly. I would consider this approach "explicit" as it forces the client to explicitly configure/instantiate your components. I think it's like providing your clients with primitives and allowing them to compose, build, and configure them in whatever way they want:
const ApiAuth = require('./amazing-time-api-auth');
const ApiTasks = require('./amazing-time-api-tasks');
module.exports = {
auth: ApiAuth,
tasks: ApiTasks
}
This automatically namespaces the api behind its functions (auth|tasks) AND requires that the client instantiatae the classes before using:
const api = require("./lib/someApi");
const auth = new api.auth(process.env.SOMETHING, 'some-url');
This pulls the configuration further out in the architecture. It forces the client to decide how it wants to get the URL and explicitly instantiate the library. What if one of your clients doesn't use login/logout? This may be more flexible in that case.
i am not sure if creating this instances everytime requiring index.js is a rigth thing
If instantiation should remain hidden, another alternative would be to provide a builder function in order to encapsulate it:
const ApiAuth = require('./amazing-time-api-auth');
const ApiTasks = require('./amazing-time-api-tasks');
apiAuth = new ApiAuth('www.sample-host.com');
apiTasks = new ApiTasks('www.sample-host.com');
module.exports = {
auth: {
build: (url) => {
return new ApiAuth(url);
}
},
tasks: {
build: (url) => {
return new ApiTasks(url);
}
}
}
This should still hide each class but still allows the client to decide how it configures each class:
const api = require("./lib/someApi");
const auth = api.auth.build('my-url');
auth.login();

Export object using module.exports = new Sample vs module.exports = Sample

Suppose a file has a lot prototypes and function object declarations code:
function Sample() {
...
}
Sample.prototype.method1 = () => {
...
}
Sample.prototype.method2 = () => {
...
}
When do I need to export this main object using? Example:
module.exports = new Sample;
// or
module.exports = Sample;
I have a few questions about this:
What signals of the project design will let me decide to use one or the other?
Does have these methods any disadvantages on using one of them (performance, prototyping inheritance)?
Can you provide a short example/s on when is it good practice to use module.exports = new Sample and when module.exports = Sample?
It depends on whether the Sample is ever going to be instantiated more than once. If it is going to be instantiated more than once by whatever consumes it, then you absolutely have to export Sample the class itself.
Otherwise, you could instantiate a Sample and export it, ensuring that there will only ever be one instantiated Sample object:
module.exports = new Sample();
Make sure to use those parentheses - you're invoking a constructor, after all.
But at this point, there isn't that much much point making a class at all - why not export a plain object instead?

Using ES6 classes OR Object Literals in controllers for an Express + NodeJS app

There are 2 things that I'm very confused about.
What is the advantage of using any of ES6 class or Object literals.
And where should I use any of them?
Some of the examples that I'm trying out are mentioned below. Please let me know when to use particular way of implementation and when not to.
Class Example 1:
// auth.js
class Auth {
login(req, res) {...}
signup(req, res) {...}
}
module.exports = new Auth();
// index.js
const auth = require('auth');
Class Example 2:
// auth.js
class Auth {
login(req, res) {...}
signup(req, res) {...}
}
module.exports = Auth;
// index.js
const Auth = require('auth');
const auth = new Auth();
Object Literal Example:
// auth.js
module.exports = {
login: (req, res) => {...},
signup: (req, res) => {...}
};
// index.js
const auth = require('auth');
What I think from reading about them is that:
Class Example 1:
You can not create more than 1 object. Because a module is only executed once. So, on every import you will get the same object. Something similar to singleton. (Correct me here if I misunderstood it)
You will not be able to access the static methods of the class because you are only exporting the object of the class.
Class Example 2:
If you have a class that contains nothing but helper methods and the object does not have any state, It makes no sense creating object of this class all the time. So, in case of helper classes, this should not be used.
Object Literal Example:
You can not do inheritance.
Same object will be passed around on every require. (Correct me if I'm wrong here as well)
Please help me understand these concepts, what I'm missing out, what I've misunderstood and what should be used when and where. I'll be very grateful for your help.
Feel free to edit the question, if you think I made a mistake somewhere.
Class Example 1: You can not create more than 1 object. Because a module is only executed once. So, on every import you will get the same object. Something similar to singleton.
Correct. This is an antipattern therefore. Do not use it. class syntax is no replacement for object literals.
You will not be able to access the static methods of the class because you are only exporting the object of the class.
Theoretically you can do auth.constructor.… but that's no good.
Class Example 2: If you have a class that contains nothing but helper methods and the object does not have any state, It makes no sense creating object of this class all the time. So, in case of helper classes, this should not be used.
Correct. Use a simple object literal instead, or even better: multiple named exports instead of "utility objects".
Object Literal Example: You can not do inheritance.
You still can use Object.create to do inheritance, or parasitic inheritance, or really anything.
Same object will be passed around on every require.
Correct, but that's not a disadvantage. If your object contains state, you should've used a class instead.
If your class has got a constructor, you can build several objects from this class threw :
var Panier= require('./panier');
var panier1 = new Panier(13, 12, 25);
var panier2 = new Panier(1, 32, 569);
Of course your Panier would be defined in the file Panier.js located in the same directory :
module.exports = class Panier
{
constructor(code, qte, prix)
{
this.codeArticle = code;
this.qteArticle = qte;
this.prixArticle = prix;
}
getCode()
{
return this.codeArticle;
}
getQte()
{
return this.qteArticle;
}
getPrix()
{
return this.prixArticle;
}
}

Parse and share obj resources in module

I wanted to know if its good practice to use it like following since I used a global field cacheObj
I need to parse the data and share it between other modules,any module can take any property but only the first module which called to this parser is responsible to provide the data to parse(I need to do this parse just once and share properties in different modules)
This code is from other SO post and I want to use it
var Parser = require('myParser'),
_ = require('lodash');
var cacheObj; // <-- singleton, will hold value and will not be reinitialized on myParser function call
function myParser(data) {
if (!(this instanceof myParser)) return new myParser(data);
if (!_.isEmpty(cacheObj)) {
this.parsedData = cacheObj;
} else {
this.parsedData = Parser.parse(data);
cacheObj = this.parsedData;
}
}
myParser.prototype = {
//remove `this.cacheObj`
getPropOne: function () {
return this.parsedData.propOne;
},
getPropTwo: function () {
return this.parsedData.propTwo;
}
};
module.exports = myParser;
It kindda looks like the Context Object pattern, which is used for maintaining state and for sharing information. Some consider it a bad practice and prefer Singleton when it comes to share the object between layers, but if suites your case (in the same module) - my advice is to use it.
UPDATE
The main reason why you shouldn't use ContextObject through your layes is because it binds all sub-systems together( one object is referencing everything else). While Singleton is not just for creating objects, it is also services as access point that can be loaded by the corresponding sub-system. Having a Singleton represent every service access point allows for seamless vertical integration of cooperating components/modules. Simple code example:
Singleton:
// returns the "global" time
var time = Clock.getInstance().getTime();
Context object:
// allows different timezones to coexist within one application
var time = context.getTimezoneOffset().getTime();

Categories