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.
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.
Is it possible to create a function somewhere that can be called from any view in my express js mvc web app? How to declare such function in middleware to be accessed directly from a view?
So I can call this function like:
<%= getVar('my_name') %> // calling from the view
and implement return logic of the variable where the function is declared. This function may use request and response objects.
Note: 'my_name' can be anything on the view which cannot be assigned from the controller.
You can add functions to app.locals or res.locals just like you would add variables to it. If you want to have the request and response available in there (which, frankly, I feel bleeds a bit into what your controllers should be doing), you could create a middleware and pass those in.
From what you said in your comment, it's actually best to just set the variable that the view can use, eg:
app.use((req, res, next) => {
res.locals.value = req.session.value || 'default value';
next();
});
if you really need the function to be usable in the view, you can set it the same way, and bind the request and response to the function if needed:
function getVar(req, res, anotherArg) {
// do whatever
}
app.use((req, res, next) => {
res.locals.getVar= getVar.bind(null, req, res);
next();
});
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
}
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.
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.