// config.js exports.port = 8080; // app.js var express = require('express'); var config = require('./config.js'); var app = express(); app.get('/hello', function(req, res) { res.end('Hello world'); }); app.listen(config.port);
At first glance, everything is fine, the code is clear, the configuration is moved to a separate file and can be changed for virgin and production. Such an implementation is found on all resources devoted to the creation of web applications on nodejs. So we laid the foundation of our error in ten lines of the purest code. But first things first. // config.js exports.port = 8080; exports.mongoUrl = 'mongodb://localhost:27017/test'; // app.js var express = require('express'); var MongoClient = require('mongodb').MongoClient; var config = require('./config.js'); // var db; MongoClient.connect(config.mongoUrl, function(err, client){ if (err) { console.error(err); process.exit(1); } db = client; }); // - var app = express(); app.get('/', function(req, res, next) { db.collection('files').find({}).toArray(function(err, list){ if (err) return next(err); res.type('text/plain').end(list.map(function(file){ return file.path; }).join('\r')); }); }); app.get('/file', function(req, res, next){ db.collection('files').findOne({path:req.query.file}).toArray(function(err, file){ if (err) return next(err); res.type('text/plain').end(file.content); }); }); app.listen(config.port);
Ok, everything is simple and clear: connect to the base, create a server, assign handles for the paths. But let's think about what disadvantages the code has: // app.js var MongoClient = require('mongodb').MongoClient; var EventEmitter = require('event').EventEmitter; var util = require('util'); module.exports = App; function App(config) { var self = this; // event emitter EventEmitter.call(this); MongoClient.connect(config.mongoUrl, function(err, db){ if (err) return self.emit("error", err); self.db = db; }); this.list = function(callback) { self.db .collection('files') .find({}) .toArray(function(err, files){ if (err) return callback(err); files = files.map(function(file){ return file.path }); callback(null, files); }); }; this.file = function(file, callback) { self.db .collection('files') .findOne({path:file}) .toArray(callback); }; } util.inherits(App, EventEmitter); // config.js exports.mongoUrl = "mongo://localhost:27017/test"; exports.http = { port : 8080 }; // http.js var App = require('./app.js'); var express = require('express'); var configPath = process.argv[2] || process.env.APP_CONFIG_PATH || './config.js'; var config = require(configPath); var app = new App(config); app.on("error", function(err){ console.error(err); process.exit(1); }); var server = express(); server.get('/', function(req, res, next){ app.list(function(err, files){ if (err) return next(err); res.type('text/plain').end(files.join('\n')); }); }); server.get('/file', function(req, res, next){ app.file(req.query.file, function(err, file){ if (err) return next(err); res.type('text/plain').end(file); }); }); server.listen(config.http.port);
What have we done? Added event model for catching errors. Added the ability to specify the configuration path for each application instance. // cli.js var App = require('./app.js'); var program = require('commander'); var app; program .version('0.1.0') .option('-c, --config <file>', 'Config path', 'config.js', function(configPath){ var config = require(configPath); app = new App(config); app.on("error", function(err){ console.error(err); process.exit(1); }); }); program.command('list') .description('List files') .action(function(){ app.list(function(err, files){ if (err) return app.emit("error", err); console.log(files.join('\n')); }); }); program.command('print <file>') .description('Print file content') .action(function(cmd){ app.file(cmd.file, function(err, file){ if (err) return app.emit("error", err); console.log(file); }); });
or test // test.js var App = require('App'); var app = new App({ mongoUrl : "mongo://testhost:27017/test" }); // : // {path:'README.md', content:'This is README.md'} app.on("error", function(err){ console.error('Test failed', err); process.exit(1); }); // nodeunit module.exports = { "Test file list":function(test) { app.list(function(err, files){ test.ok(Array.isArray(files), "Files is an Array."); test.equals(files.length, 1, "Files length is 1."); test.equals(file[0], "README.md", "Filename is 'README.md'."); test.done(); }); } }
Of course, the application now does not look as minimalistic as in the examples, but it is more flexible. In the next part I will tell about catching errors.Source: https://habr.com/ru/post/241788/
All Articles