I have an Express route defined as follows (where app is my Express app):
module.exports = function(app) {
var controller = require('../../app/controllers/experiment-schema');
app.route('/api/experiment-schemas/random').get(controller.random);
};
In that 'controller' file, I have this method:
exports.random = function (req, res, callback) {
ExperimentSchema.count({}, function (err, count) {
var rand = Math.floor(Math.random() * count);
ExperimentSchema.find({})
.skip(rand)
.limit(1)
.populate('mediaPool', 'artist title label')
.exec(function (err, schema) {
res.json(200, schema);
if (typeof callback === 'function') {
callback();
}
});
});
}
Here, ExperimentSchema is a Mongoose model. Since the controller method hits the database, I'm passing in a callback in my test so that I can wait for those database calls to return and verify the return value. I'm doing this based on this question.
When I go to test the route, I'm testing with supertest, actually making the HTTP call to the route. The problem is that when I do this, Express is injecting next as the third argument to my random method. Now, callback() aliases next(), and everything goes haywire. How can I test my route and my controller seperately?
The best way to test controller functions like that is to just mock the request and response data and export it to a test suite like mocha. Though it also seems like you will need to mock out your mongoose schema's as well. There is no easy way to test these components unless you want to mock the inputs for these functions.
I fixed this by refactoring the route to expect only the default parameters req and res.
Related
I could not find the official docs in a google search. Where are the official API docs for express.Router() and are lines 1 and 2 the same?
If so, is it just a matter of preference on which to use?
const express = require('express');
const router = express.Router();
router.get('path', callback); // line 1
router.route('path').get(callback); // line 2
There are 3 ways with which you can declare routes in your application
These are:
app.get("path", fn)
router.get("path", fn)
router.route("path").get(fn)
All of the above functions are used to generate http request routes in your application.
The app.get is the most basic one and is not recommended for larger projects. The reason being it gives less flexibility in handling routes as compared to the express.router. In express applications you will be dealing with middlewares a lot. Middlewares are functions that are executed before the controller function of your application
For example, take a look at this line
app.get("/user", verifyUser, createUser);`
Above, verifyUser is a middleware function that is called with (Request, Response, Next) arguments by the express framework, you can write your incoming request verification logic in verifyUser and can then callNextFunctionto pass the control to the next function with is thecreateUsercontroller;
You can have as many middlewares as you want in your route declaration.
What if you need to call verifyUser each time a user is created, removed, fetched or modified. For each of the actions, you need to define your routes like this:
app.get("/user", verifyUser, fetchUser);
app.put("/user", verifyUser, updateUser);
app.post("/user", verifyUser, createUser);
app.delete("/user", verifyUser, deleteUser);
In larger applications you need to defined different logics to different entities and routes.
express.router solves the above problem by providing us a flexibility to define what to do when user lands the /user route before passing the request to the middleware.
The above code in express router can be written as follows:
// file: userRoutes.js
const router = express.Router();
router.use((req, res, next) => {
verifyUser(req, res, next);
});
function verifyUser(req, res, next) {
// verification logic here
if (/** verification is successful */)
return next(); // return to the controller
res.status(400).json({ msg: "user does not exists" });
}
router.get("/user", fetchUser);
router.put("/user", updateUser);
router.post("/user", createUser);
router.delete("/user", deleteUser);
module.exports = router;
// app.js
const userRoutes = require("./userRoutes");
app.use(userRoutes);
Things gets really simplified if we chain the http request methods in the following way:
router.route("/user")
.get(fetchUser);
.put(updateUser);
.post(createUser);
.delete(deleteUser);
Note: Above code is for explanation purpose only, there may be syntax errors, the code is not expected to run as it is. User might need to alter the code to make it work.
Lets say I've some REST api server (maybe Express one).
When the life cycle begins (i.e someone GET 'http://foo/bar') there is some data in the Request object.
So let's say I've got something like this:
const method1 = require('some-module').method1;
app.get('/foo/bar', (req, res, next) => {
method1();
});
I want a simple way in the some-module.js to get a winston instance that somehow knows about all relevant data so I don't need every time to pass the request object all over my code.
The trivial solution is to pass the method1 the object and inside do like
method1(req){
winston.info('my message', {requestId: req.id};
}
But this is ugly because I need to change the signature of all my stuff just for logs.
Another option is to make everything a class that extends winston and do something like
app.get('/foo/bar', (req, res, next) => {
const foo = new Foo(new winstonWrapper(req));
});
and than foo.info('msg') will call something like winston.info('msg',{reqId:req.id})
What an elegant way can you suggest to create a winston instance upon request and use it in other modules easily?
I'm writing some rest API with Node.JS and Express. So for each API, I'd need to do all the usual stuff like parameter validation, authentication, authorization and then the actual business logic. Some sodo code to illustrate this:
router.get('/users', function (req, res){
async.auto(
authenticateCaller();
authorizeCaller();
validateParams();
doGetUsers();
)
})
This style certainly works but it makes the whole function very cumbersome by including a lot of extra pre-purpose codes. I know in web app programming, MVC has been introduced to separate UI, Module and Controller into different code groups, which is much cleaner. Is there any similar framework that can be helped to achieve this purpose?
Use middleware. Middleware is just a function that takes in three parameters:
function (req, res, next) {}
Call router.use() to register middleware before defining any routes. This will cause that middleware to be called before every route is executed.
These are all functions of middleware:
authenticateCaller();
authorizeCaller();
validateParams();
http://expressjs.com/en/guide/using-middleware.html
This is what I do.
Using Routes for Node.js Here I am making way for a folder named routes that has all the codes in it.
var routes = require('./routes');
var route_add_user = require('./routes/add_user');
Calling the function with the route here; .adduser is function name within that js file
app.get('/adduser', route_add_user.adduser);
define a function do your routine jobs
fuction auth(res,req,next){
authenticateCaller();
req.isAuthorized = authorizeCaller();
validateParams();
next();
}
router.get('/users',auth);
router.get('/users', function (req, res){
if( req.isAuthorized)
{..do some stuff here..}
})
This is one of the STYLE i was following to authenticate and use the API in express framework.
register.js
-----------
exports.addUser = function(req, res) {
// do something
};
exports.deleteUser = function(req, res) {
// do something
};
routes.js
---------
var register = require('./register');
router.get(‘/register’,auth, register.addUser);
router.get(‘/deleteUser’,auth, register.deleteUser);
// Better make it separate common file to reuse all the API
function auth(req,res,next) {
// do something to authenticate your API
}
Im creating an API REST with express and nodejs and im on the early phase of my routing.
My idea is create "controllers" for every route separated and call that controller in a router file, something like:
...
router.post('/login', loginCtrl.login(req, res));
In other project i handled that with a simple object of functions, requiring it and then just calling that functions. Now my idea is something more interesting, im working with the object constructor, like:
var ctrl = function() {
this.login = function(req, res) {
res.json({ msg: 'hello' }); // just an example
}
}
Im writing this on coffeescript (the client wants coffee, so...) and the sintax is with that metalanguage but at least is identic, my problem is with req and res, this is my router file:
express = require 'express'
router = express.Router()
###
Rutas de autenticación
###
AuthController = require '../controllers/authenticate'
auth = new AuthController()
router.post '/setup' , auth.setup req, res
router.post '/register', auth.register req, res
router.post '/login' , auth.login req, res
module.exports = router
When the server runs, it throws me this error:
/home/nano/Dev/erp-api/app/routes/apiroutes.coffee:17
router.post('/setup', auth.setup(req, res));
^
ReferenceError: req is not defined
Exactly why this happens? I have no idea, it works when i worked with plain objects.
Like you did you are calling the function setup with the variables, while what you want is to pass the reference to the function. so you have to just pass the reference to it and not executing it.
router.post '/setup' , auth.setup
req, res will automatically be passed to that function.
I'm using ExpressJs with Node.js and have put all my routes into a 'routes' folder.
On the server, I do my DB connection, then define my routes, like this:
var routes = require('./routes');
var db;
dbconnect = new mongo.Db(config.mongo_database, new mongo.Server(config.mongo_host, config.mongo_port, {}), {});
dbconnect.open(function (err, db) {
db.authenticate(config.mongo_user, config.mongo_pass, function (err, success) {
if (success) {
//routes/index.js
app.get('/', routes.index);
//routes/users.js
app.get('/users', routes.users);
}
});
});
I want to access the 'db' object inside each of these routes javascript files. How would I pass that from this 'app.js' file to the index.js or users.js?
Thank you!
If you write your database abstraction in it's own file/module, you can then reuse it throughout your codebase as needed by just require()'ing it where needed. It won't get re-created if you write it correctly, and can just get initialized once on application startup like your example does.
//contents of your database.js file
var database;
module.exports = {
init : function(config, cb) {
database = new mongo.Db(config.mongo_database, new mongo.Server(config.mongo_host, config.mongo_port, {}), {});
database.open(function (err, db) {
db.authenticate(config.mongo_user, config.mongo_pass, cb);
});
},
query : function(params, cb) {
database.query(params, cb);
}
};
This is a trivial example, but hopefully it gets the point across. In controllers or any files where you need that database object, you just...
var db = require('database');
db.init(params, function(err, db) {
...
});
db.query(params, function(err, db) {
...
});
The benefits are you now have a loosely coupled database object that can be used anywhere in your application just like any other node module through the require statement.
One suggestion is to expose your routes via a function which accepts a db parameter:
routes.js:
module.exports = function(db) {
return {
index: function(req, res, next) {
// Funky db get stuff
}
}
}
Wrapping values in a closure like this and returning an object with more functions is a useful pattern, sometimes called "Revealing Module Pattern". It shows the dependencies clearly, allowing for easy testing (using e.g. a mock db object) while still using a flexible functional approach.