Breaking up node module code (for a library/api client) - node.js

I'm writing a node module to consume a REST API for a service. For all intents and purposes we might as well say it's twitter (though it's not).
The API is not small. Over a dozen endpoints. Given that I want to offer convenience methods for each of the endpoints I need to split up the code over multiple files. One file would be far too large.
Right now I am testing the pattern I will outline below, but would appreciate any advice as to other means by which I might break up this code. My goal essentially is to extend the prototype of a single object, but do so using multiple files.
Here's the "model" I'm using so far, but don't think is really a good idea:
TwitterClient.js
function TwitterClient(){
this.foo = "bar";
}
require("fs").readdirSync("./endpoints").forEach(function(file) {
require("./endpoints/" + file)(TwitterClient);
});
var exports = module.exports = TwitterClient;
endpoints/endpointA.js etc
module.exports = function(TwitterClient){
TwitterClient.prototype.someMethod = function(){
//do things here
}
}
The basic idea obviously is that any file in the endpoints folder is automatically loaded and the TwitterClient is passed in to it, so that it's prototype can be accessed/extended.
I don't plan to stick with this pattern because for some reason it seems like a bad idea to me.
Any suggestions of better patterns are very much appreciated, cheers

Related

console.log() not appearing in output for express server

I can't for the life of me figure out how to get console.log() to appear with my express server. It's a middle-tier API for our front-end. You'll have to forgive me if I speak about it a little awkwardly, I'm relatively inexperienced with these tools but I'll do my best to explain the issue despite my inexperience. I'm trying to use console.log to get a better idea of a rather complex projects behavior and what might be causing some issues with it in its current state. Unfortunately console.log only seems to work within plainjane examples like so:
export const routerExample = express.Router();
routerExample.use((req, res, next) => {
console.log('Time: ', Date.now()); // I show up in console just fine
next();
});
When I try to lookup the problem I'm experiencing all solutions seem to be regarding getting routing examples like the one above to appear in console, I can see such examples just fine. The problem comes from getting anything to show up in examples like:
// routing.ts
import { homeController } from '../controllers/homeController';
const homeEx: HomeExample = new HomeExample();
routerExample.get('/home', homeEx.getHome);
// homeController.ts
export class HomeExample {
public getHome (req: Request, res: Response) : void {
console.log("something is happening");
// do stuff
}
}
Any uses of console.log like above never appear anywhere in node's console (or elsewhere as far as I can tell).
What am I missing that is needed to make these log messages appear? This has to be incredibly simple but I've been through numerous similar sounding issues on stackoverflow and elsewhere and everything single of one of them seems to be describing slightly different issues (or misunderstandings) that don't solve my own issue. I've tried numerous versions of node/npm and have added the DEBUG:* flag as well. None of this seems to solve it. If I'm missing any code that'd help give context to the issue let me know. I've obviously cut down parts and renamed some objects as I can't exactly dump work-related code here. What am I missing? Any help would be greatly appreciated :)
Edit 1: since many similar posts to this seem to get this mixed up, no I'm not looking at my front-end's console or something for the output. I'm looking in the terminal window where I start the server from, where the router example does appear.
Edit 2: for reference, my file structure is something like:
app/
controllers/
homeController.ts (HomeExample stuff is here)
routes
routing.ts (routerExample stuff is here)
app.ts
...
Edit 3: the code works overall to be clear. the problem is explicitly that that log.console() isn't appearing, all the code I've wrapped into "// do stuff" is working as expected.
Checkout Express Middlewares
routerExample.get('/home', homeExample);
function homeExample (req: Request, res: Response, next:NextFunction) : void {
console.log("something is happening");
// do stuff
}
}
You are also calling a member of a non static or instantiated class see this:
TypeScript - Static
What you are missing is to create a new instance of the homeExample class. What I recommend is to export the new instance on the route file like this:
/routes/home.route.js
class HomeRoute {
/* your methods */
}
export default new HomeRoute();
then you can use it:
import homeRoutes from './routes/home.route';
router.get('/home', homeRoutes.getHome);
See the example:
https://replit.com/#abranhe/expressjs-console-log#index.js
After a fresh nights sleep I've figured it out. It, of course, was the most obvious problem that managed to slip by me in the overall complexity of the codebase. The /home call was deprecated and replaced with a different call in the front-end without mention in the middle-tier code that I had posted. I didn't even consider checking what was being called any deeper since I was experiencing the same issue with multiple other calls that I didn't include in the original post for brevity. Basically all the tools I'm working with here are completely new to me so my inexperience got the best of me. Thank you to #jfriend00 who made me double-take how /home was being called (it wasn't).
Since I was getting the data I needed without issue on the front-end I assumed these functions were being run, seeing as the data they produced was the same kind of data that was successfully being shown by the front-end, just without the console.log() output I added appearing.
Moral of the story: if every other question related to an issue on Stack Overflow concludes with "I just made a dumb mistake," take absolutely every precaution possible to observe what's happening, even if you feel like you already ruled out certain possibilities. Unfortunately I got a bit caught up with all the weird solutions I saw to the point where I got ahead of myself in debugging the problem.
I'm still a bit confused since the /home call specifically should still be "active" even if not called by the front-end, but console.log() is clearly working on other similar functions I've tested since figuring this out. There's either something hidden deep in the codebase that's breaking/overwriting /home and other old calls, or it's simply not being called right when I'm testing it outside of the front-end.
TLDR: I'm an idiot, every single API call I thought I was testing was not actually being called. Double-check your assumptions before asking for a specific solution.

Testing Involving Database

well before specifying my problem, i want to tell that i'm new to the field of testing, so here is my problem:
i developed a rest api using express + sequelize(mysql), and i want to write some test for my api. i choosed to use jasmine library for testing.
so right know i want to test the create and update rest endpoint, i will need access to a database, but the problem is that the test cases are run in parallel, and there is only one database, so if i want to delete all item from a table in a test case, and another test case have create a row in that table, there will be a problem.
const request = require('superagent');
const models = require('../../src/models');
const Station = models.Station;
describe("station testing", function () {
before(() => {
// delete and recreate all database table
// before running any test
});
describe("crud station", function () {
it('should create model', () => {
Station.create({
'name': 'test',
lat: 12,
long: 123,
}).then( model => {
expect(model).toBeTruthy();
});
});
it('should delete evrything', () => {
Station.deleteAll().then( () => {
// problem here if after the first model is created and before create model except is executed
expect(Station.Count()).toEqual(0);
}
});
});
});
Your problem is that you are not writing unit tests here.
You need to understand the most important rule of unit testing - only test one unit at a time. A unit can be thought of as an area of your code. In a traditional desktop project (Java, C#, etc), a unit would be one class. In the case of Javascript, a unit is harder to define, but it certainly will only include the Javacript. If you are including any server code (for example, the database) in your tests, then you are not unit testing, you are doing integration testing (which is also very important, but much harder).
Your Javascript will have dependencies (ie other code that it calls, say via Ajax calls), which in your case will include the server code that is called. In order to unit test, you need to make sure that you are only testing the Javascript, which means that when running the tests, you don't want the server code to be called at all. That way, you isolate any errors in that unit of code, and can be confident that any problems found are indeed in that unit. If you include other units, then it could be the other units that have the problem.
In a strongly-typed language (like Java, C#, etc), there are frameworks that allow you to set up a mock for each dependency. Whilst I haven't tried any myself (that's this week's job), there are mocking frameworks for Javascript, and you would probably need to use one of them to do real unit testing. You mock out the server code, so when you run the test, it doesn't actually hit the database at all. Apart from solving your problem, it avoids a whole load of other issues that you will likely hit at some point with your current approach.
If you don't want to use a mocking framework, one other way to do it is to change your Javascript so that the function you are testing takes an extra parameter, which is a function that does the actual server call. So, instead of...
deleteCustomer(42);
deleteCustomer(id) {
validate(id);
$.ajax(...);
}
...your code would look like this...
deleteCustomer(42, callServer);
deleteCustomer(id, serverCall) {
validate(id);
serverCall(id);
}
...where serverCall() contains the Ajax call.
Then, to unit test, you would test something like this...
deleteCustomer(42, function(){});
...so that instead of calling the server, nothing is actually done.
This is obviously going to require some rewriting of your code, which could be avoided by mocking, but would work. My advice would be to spend some time learning how to use a mocking framework. It will pay off in the long run.
Sorry this has been a bit long. Unfortunately, you're getting into a complex area of unit testing, and it's important to understand what you're doing. I strongly recommend you read up about unit testing before you go any further, as a good understanding of the basics will save you a lot of trouble later on. Anything by Robert Martin (aka Uncle Bob) on the subject will be good, but there are plenty of resources around the web.
Hope this helps. If you want any more info, or clarification, ask away.
Jasmine supports a function for beforeEach which run before each spec in a describe block.
You can use that.
describe("A spec using beforeEach and afterEach", function() {
var foo = 0;
beforeEach(function() { foo += 1; });
afterEach(function() { foo = 0; });
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
it("can have more than one expectation", function() {
expect(foo).toEqual(1)
expect(true).toEqual(true);
});
});
So you could let the beforeEach take care of the delete operation.

Where should I put custom errors in sails.js?

I was wondering what's the best practice and if I should create:
a directory in which declare statically all the errors my application uses, like api/errors/custom1Error
declare them directly inside the files
or put the files directly inside the dir that needs that error, like api/controller/error/formInvalidError
other options!?
A neat way of going about this would be to simply add the errors as custom responses under api/responses. This way even the invocation becomes pretty neat. Although the doc says you should add them directly in the responses directory, I'm sure there must be a way to nest them under, say, responses/errors. I'll try that out and post an update in a bit.
Alright, off a quick search, I couldn't find any way to nest the responses, but you can use a small workaround that's not quite as neat:
Create the responses/errors directory with all the custom error response handlers. Create a custom response and name it something like custom.js. Then specify the response name while calling res.custom().
I'm adding a short snippet just for illustration:
api/responses/custom.js:
var customErrors = {
customError1: require('./errors/customError1'),
customError2: require('./errors/customError2')
};
module.exports = function custom (errorName, data) {
var req = this.req;
var res = this.res;
if (customErrors[errorName]) return customErrors[errorName](req, res, data);
else return res.negotiate();
}
From the controller:
res.custom('authError', data);
If you don't need logical processing for different errors, you can do away with the whole errors/ directory and directly invoke the respective views from custom.js:
module.exports = function custom (viewName, data) {
var req = this.req;
var res = this.res;
return res.view('errors/' + viewName, data);//assuming you have error views in views/errors
}
(You should first check if the view exists. Find out how on the linked page.)
Although I'm using something like this for certain purposes (dividing routes and so on), there definitely should be a way to include response handlers defined in different directories. (Perhaps by reconfiguring some grunt task?) I'll try to find that out and update if I find any success.
Good luck!
Update
Okay, so I found that the responses hook adds all files to res without checking if they are directories. So adding a directory under responses results in a TypeError from lodash. I may be reading this wrong but I guess it's reasonable to conclude that currently it's not possible to add a directory there, so I guess you'll have to stick to one of the above solutions.

Attaching object to Node.js process

I am using the environment variable and arguments parsing module called nconf for my node.js Express web server.
https://github.com/indexzero/nconf
I decided that the best way to make the nconf data global was to simply attach it to the process variable (as in process.env), is this a good idea or bad idea? Will it slow down execution in weighing down "process"?
Here is my code:
var nconf = require('nconf');
nconf.argv()
.env()
.file({ file: './config/config.json' });
nconf.defaults({
'http': {
'port': 3000
}
});
process.nconf = nconf;
//now I can retrieve config settings anywhere like so process.nconf.get('key');
frankly, I kind of like this solution. Now I can retrieve the config data anywhere, without having to require a module. But there may be downsides to this...and it could quite possibly be a very bad idea. IDK.
It won't slow down the execution, but feels "smelly". It's hard to discover, and it will be difficult to test, if you ever decide you need to.
A better solution would be to attach settings to a module and use require() to import it wherever needed.
The best solution would be to just pass your settings object to the classes or modules that need it. Either directly, or as part of some kind of "global context".
Eg.
var global = {
settings: {
port: 8080
}
}
//...
global.api = new Api(global);
//...
function Api(global) {
var port = global.settings.port;
}
UPDATE: more info on why the original pattern is bad:
1) Discoverability
You attach your settings to process.settings and go off to a different project. A year later, someone else takes over or you need to update things. Will you remember you attached your settings to process.nconf? Or was it process.settings?
Now imagine you have 10 different global things, attached under different names, on different places.
It's not as bad as attaching directly to the global context, but it's certainly better to clearly see where the stuff you're using is coming from (constructor or module).
2) Testing
You decide you need to test your module. So now you need to tweak your settings for each test instead of loading them from a file or argv. How do you do that?
In case of the global process.nconf or require("settings") patterns, you need to do something like this:
function canOpenAPIOnTheConfiguredPort(done) {
var nconfSaveApiPort = process.nconf.api.port;
process.nconf.api.port = '1234';
var api = new Api();
test.assertEqual(api.port, '1234');
process.nconf.api.port = nconfSaveApiPort;
done();
}
As your application grows, this quickly becomes annoying (eg. imagine having to mock 10 things). In comparison, here's how you do it using the dependency injection (constructor) pattern.
function canOpenAPIOnTheConfiguredPort(done) {
var api = new Api({
port: '1234'
});
test.assertEqual(api.port, '1234');
done();
}
Notice that nconf is a singleton.
I use to configure at the very beginning of the program and then when I need a setting in another file I do:
var nconf = require ('nconf');
nconf.get('x');

node.js - eval'ing to a live process

Did anyone set up something like this for himself using the existing
node.js REPL? I didn't think of a quick way to do it.
The way I do it today is using emacs and this:
https://github.com/ivan4th/swank-js
This module is composed of:
A SLIME-js addon to emacs which, in combination with js2-mode, lets
you simply issue a C-M-x somewhere in the body of a function def - and
off goes the function's string to the ..
Swank-js server (yes, you could eval from your local-machine
directly to a remote process) written in Node.js - It receives the
string of the function you eval'ed and actually evals it
A whole part that lets you connect to another port on that server
with your BROWSER and then lets you manipulate the DOM on that browser
(which is pretty amazing but not relevant)
My solution uses SLIME-js on the emacs side AND I require('swank-
js') on my app.js file
Now.. I have several issues and questions regarding my solution or
other possible ones:
Q1: Is this overdoing it? Does someone have a secret way to eval stuff
from nano into his live process?
Q2: I had to change the way swank-js is EVALing.. it used some
kind of black magic like this:
var Script = process.binding('evals').Script;
var evalcx = Script.runInContext;
....
this.context = Script.createContext();
for (var i in global) this.context[i] = global[i];
this.context.module = module;
this.context.require = require;
...
r = evalcx("CODECODE", this.context, "repl");
which, as far I understand, just copies the global variables to the
new context, and upon eval, doesn't change the original function
definitions - SOOO.. I am just using plain "eval" and IT
WORKS.
Do you have any comments regarding this?
Q3: In order to re-eval a function, it needs to be a GLOBAL function -
Is it bad practice to have all function definitions as global (clojure-like) ? Do you think there is another way to do this?
Actually, swank.js is getting much better, and it is now much easier to set up swank js with your project using NPM. I'm in the process of writing the documentation right now, but the functionality is there!
Check this out http://nodejs.org/api/vm.html
var util = require('util'),
vm = require('vm'),
sandbox = {
animal: 'cat',
count: 2
};
vm.runInNewContext('count += 1; name = "kitty"', sandbox, 'myfile.vm');
console.log(util.inspect(sandbox));
// { animal: 'cat', count: 3, name: 'kitty' }
Should help you a lot, all of the sandbox things for node uses it :) but you can use it directly :)
You might take a look at jsapp.us, which runs JS in a sandbox, and then exposes that to the world as a quick little test server. Here's the jsapp.us github repo.
Also, stop into #node.js and ask questions for a quicker response :)

Resources