Node / Express - Refactoring Routes - node.js

I have the following node / express code;
// Requires
var app = require("express")();
var handler = require("./routes/session");
// Routes
app.post("/session", handler.sessionGetNew);
app.get("/session", handler.sessionGetAll);
app.get("/session/:sessionid", handler.sessionGetOne);
app.put("/session/:sessionid", handler.sessionUpdate);
app.delete("/session/:sessionid", handler.sessionDelete);
// Listener
app.listen(9000);
console.log("Listening.....");
Is there any way to refactor the routes to something like this pseudcode?
app.route("/session"),
.post(handler.session....)
.get(handler.session.....)
app.route("/session/:sessionid"),
.post(handler.session....)
.get(handler.session....)
.put(handler.session....)

You can use Router Middleware
app.js
var app = require('express')();
var session = require('./routes/session');
app.use('/session', session);
app.listen(9000, function() {
console.log('listening');
});
routes/session.js
var router = require('express').Router();
var handler = require('./lib/sessionHandler'); // this was 'handler' in app.js
router.post('/', handler.sessionGetNew);
router.get('/', handler.sessionGetAll);
router.get('/:sessionid', handler.sessionGetOne);
router.put('/:sessionid', handler.sessionUpdate);
router.delete('/:sessionid', handler.sessionDelete);
module.exports = router;

This gives you approximately what you want
function routReductor(route, methods) {
var goodMethods = ['get', 'post', 'put', 'delete'];
for (var key in methods) {
if (goodMethods.indexOf(key) == -1) continue;
app[key](route, methods[key])
}
}
routReductor('/:sessionid', {
get: handler.sessionGetOne,
put: handler.sessionUpdate,
delete: handler.sessionDelete
});

Related

how to add custom function to express module

I am trying to add a method
loadSiteSettings to express module
In app.js
var express = require('express');
var path = require('path');
var mongoose = require('mongoose');
//Set up default monggose connection for mongo db
var mongoDB = 'mongodb+srv://***:*****#cluste******j.mongodb.net/cms?retryWrites=true&w=majority';
mongoose.connect(mongoDB,{useNewUrlParser: true});
//Get the default connection
var db = mongoose.connection;
//Bind connection to error event (to get notification of connection errors)
db.on('error',console.error.bind(console, 'MongoDB connection error:'));///????????
var app = express();
///////////////////////////////////////////////////////////
var indexRouter = require('./routes/index');
app.loadSiteSettings = async function()
{
let setting = await db.collection('settings').findOne();
app.locals.siteSettings = setting;
}
app.loadSiteSettings();
//////////////////////////////////////////////////////
module.exports = app;
Index.Js for router
var express = require('express');
var router = express.Router();
var app = require('../app');
var util = require('util');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
///////////////////////////////////////////
router.get('/reloadSettings', function(req,res,next){
app.loadSiteSettings();
})
///////////////////////////////////////
module.exports = router;
so problem lies here, when server start it calls app.loadSiteSettings() in app.js
but when i use route '/reloadSettings' it seems app is undefined in index.js
This is an issue with circular dependencies and module.exports. This answer shows the same problem.
What's happening is app.js is required first and starts processing. The important thing to understand is that a file pauses execution while requiring a new file.
So when app.js requires ./routes/index, it has not finished processing, and has not reached module.exports = app. This means that when your routes file requires app.js, it's requiring it in its current state, which is the default export {}.
Thankfully there's a very simple fix:
// can be imported and tested separately from the app
const loadSiteSettings = function() {
return db.collection('settings').findOne();
}
router.get('/reloadSettings', async function(req,res,next){
let settings = await loadSiteSettings();
req.app.locals.siteSettings = settings
res.send(200); // signal the response is successful
})
This explains the issue in a lot more depth in case you're interested

how to use Wildcards in koa-route

var path = require('path')
var route= require('koa-route');//路由
app.use(route.get('/api/*',api.before));
I can't use it for this,how should I use wildcards in koa-route? Or,which other can do ?
I've been using https://github.com/alexmingoia/koa-router. I found koa-route too limiting.
It allows RegExp matching:
app.use(require('koa-router')(app));
// Matches '/test', '/test/foo/bar', '/test/foo/bar?page=2'
// but does NOT match '/test-route'
app.get(/^\/test(?:\/|$)/, function*() {
this.body = 'Test';
});
It looks to me like you're trying to attach middleware on /api/* that will run before all /api/* routes (like for authentication). This is how you can do that with koa-router:
///////////////////////////////////////////////////////////////////
// File: routes/api.js
///////////////////////////////////////////////////////////////////
var Router = require('koa-router');
// Create a router instance to bind middleware/routes to.
// Our module will export it so that our main routes.js file can
// mount it to our app.
var router = new Router();
// Middleware that ensures that a user is logged in for
// all routes attached to this router.
router.use(function*(next) {
this.assert(this.currentUser, 403);
yield next;
});
router.get('/test', function*() {
this.body = 'You went to /api/test';
});
module.exports = router;
///////////////////////////////////////////////////////////////////
// File: routes.js
///////////////////////////////////////////////////////////////////
var app = require('koa')();
var mount = require('koa-mount');
var apiRouter = require('./routes/api');
app.use(mount('/api', apiRouter.routes()));
If you navigate to /api, it'll be handled by the / handler in the router since you mounted it to /api, and it will return 403 unless you are logged in.
For
app.use(route.get('/api/*',api.before));
In api.before:
/api/a/b/c
==>
ctx.params[0] ; // => a/b/c

Express4 app.get don't wait library call for continue

I have an express 4 node application with following.
My problem is app.get don't wait to finish exectuion of getAllFsRiver and return nothing.
How to do this?
in app.js
var api1 = require('./routes/api1.js');
app.use(api1) ;
in route/api1.js
*jslint node: true */
'use strict';
var express = require('express');
module.exports = express();
var app = module.exports;
var esclient = require('../lib/esclient') ;
/* GET api vers 1 . */
app.get('/api/1/settings/rivers/fs*', function (req, res) {
var allriver = esclient.getAllFsRiver() ;
console.log("route");
res.json(allriver);
Here res.json is called before esclient.getAllFsRiver has finish execution
My guess is that getAllFsRiver is asynchronous and probably takes a callback. You should pass a callback to the function and handle the response within the callback.
esclient.getAllFsRiver(function (err, json) {
if (err) {
return res.status(500).end();
}
res.json(json);
});
Sorry, I can't add comment. Could you add getAllFsRiver implementation to the question? Maybe it is an async call.
You have must write you route kind of:
*jslint node: true */
'use strict';
var express = require('express');
var router = express.Router();
router.get('/api/1/settings/rivers/fs*', function (req, res) {
var allriver = esclient.getAllFsRiver() ;
console.log("route");
res.json(allriver);
/* ... */
})
module.exports = router;
In you code you exporting from you route new express app, that wrong
adding a callback ti my function. Ok

NodeJS and SocketIO. How to organize exposing the SocketIO instance

I have an app.js file like so:
...
var socket = require('./app/sockets')(io)
var routes = require('./app/routes')(server, socket)
...
The sockets.js looks like so:
exports = module.exports = function(io) {
return {
emit: function() {
io.emit('hi', "Some stuff")
}
}
}
The routes.j file looks like so:
exports = module.exports = function(app, io) {
...
var user = require('./controllers/user')(io)
app.get({ path: '/users/:id', version: '1.0' }, user.getUserById);
...
}
Finally, my user.js file looks like so:
exports = module.exports = function(io) {
return {
...
getPersonById: function(req, res, next) {
....
io.emit("Hello")
...
},
....
}
}
Is there a better way to organize this? I feel like I am threading my io instance through 4 different files. I just want a singleton instance I can emit events on, from within my controller.
I,m using something like this, in express.io :
app.js
var router = require('./routes/router'),
express = require('express.io'),
app = new express();
app.http().io();
app.use(app.router);
app = router.index(app);
app.listen(3000);
./routes/router.js
exports.index = function(app){
var IndexIo = require(__maindir + '/routes/io/IndexIo');
app.io.route('page/action', IndexIo.action);
app.io.route('page/action2', IndexIo.action2);
return app;
};
/routes/io/IndexIo.js
exports.action = function(req){
doSomething();
req.io.emit('doSomething', {});
}
exports.action2 = function(req){
doSomething();
req.io.emit('doSomething', {});
}

Express-resource pass additional data from app.js to routes

I would like to pass additional data from app.js to express-resource routes and I have not figured out yet. How would you do that? Note that I'm using express-resource
// app.js
var myAddOnData = 'abc';
app.resource('users', './routes/user');
// user.js
exports.index = function (req, res) {
console.log(myAddOnData);
};
Thanks
These are the three approaches I can think of. Without the little I know about your specific problem, it sounds like middleware might be the way to do it.
With a global app variable
Create a value using app.set in app.js and then retrieve it using app.get in user.js.
Using a module
Store the information in an isolated module, then require() as needed. If this is running across multiple instances, you'd obviously want to store the values to disk as opposed to in memory.
// keystore.js
// -----------
module.exports.set = function(id, val) { /* ... */ };
module.exports.get = function(id) { /* ... */ };
// app.js
// -----------
var ks = require('./keystore');
ks.set = function("userInfo", "abc");
module.exports.get = function(id) { /* ... */ };
// user.js
// -----------
var ks = require('./keystore');
ks.get = function("userInfo", "abc");
(Maybe check out pot?)
Using Middleware
Use custom middleware to attach data to the request object which can then be accessed later in the route handlers.
//app.js
//------
var express = require('express')
, cookieSessions = require('./cookie-sessions');
var app = express();
app.use(express.cookieParser('manny is cool'));
app.use(cookieSessions('sid'));
// ...
//cookie-sessions.js
//------------------
module.exports = function(name) {
return function(req, res, next) {
req.session = req.signedCookies[name] || {};
res.on('header', function(){
res.signedCookie(name, req.session, { signed: true });
});
next();
}
}
via https://gist.github.com/visionmedia/1491756

Resources