what´s the best way if I want to make a GET request in a route?
api.js
api.route('/guests')
.get(function(req, res) {
Guest.find(function(err, guests) {
if (err)
res.send(err);
res.json(guests);
});
});
routes.js
app.get('/export', requiresLogin, function(req, res) {
/* make a GET request to my api (eg.: 'api/guests') */
/* and save the 'guests' to a variable */
});
First Solution
Instead of calling internal apis, you can define a controller guestCtrl.js and call the function from guestCtrl.js in api.js and routes.js
guestCtrl.js
module.exports = {
getGuests : function(){
Guest.find(function(err, guests) {
if (err)
//handle error
return [];
else
return guests;
});
}
}
api.js
//path of guests.js
var guestCtrl = require('guestCtrl.js');
api.route('/guests').get(function(req, res) {
return guestCtrl.getGuests();
});
routes.js
var guestCtrl = require('guestCtrl.js');
app.get('/export', requiresLogin, function(req, res) {
var guests = guestsCtrl.getGuests();
// do whatever you like to do with guests
});
Second Solution
If you really want to work with internal api, then you can use request module.
e.g.
routes.js
var request = require('request');
app.get('/export', requiresLogin, function(req, res) {
// you can put the hostname and port here
request('http://127.0.0.1:3000/api/guests', function(err, body, response){
var guests = body; // and save the 'guests' to a variable
});
});
Related
I want to keep routes separate from controller.
My route is:
'use strict';
module.exports = function(app) {
var controller = require('../controllers/controller');
app.route('/').get(controller.index);
};
And controller is:
exports.index = function() {
request = new Request(
"MYQUERY",
function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
}
);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(column.value);
}
});
});
connection.execSql(request);
};
I am able to see the result in the terminal console but I want to return it as JSON to http. I can use the following if I am using controller and routes all together:
router.get('/about', function (req, res) {
res.send('About this wiki');
})
The callback function to .get (or any router request handler) takes at least two arguments: request and response. You can see this with your example:
router.get('/about', function (req, res) {
res.send('About this wiki');
})
You could rewrite this to make the callback a named function rather than an anonymous function:
const aboutHandler = function (req, res) {
res.send('About this wiki');
});
router.get('/about', aboutHandler);
Your controller.index is the same kind of function, so it will take those two arguments. You just have to change your function to take them:
exports.index = function (req, res) {
This will give you access to res, and you can use it as you need to do send the response via res.send or res.json if you build a JSON object by accumulating the row results. You can use request.on('end' ... to know when the query has emitted all its results.
I might be misunderstanding your question, but do you mean res.json(...);?
Is there a way that I can assert the middleware is actually attached to the route in my unit test below?
The server ..
var express = require('express');
var http = require('http');
var app = express();
var server = http.createServer(app);
var PORT = 5000;
var myModule = require('myModule');
var handler = require('handler');
var myMiddleware = myModule.doStuff(server);
app.use('/', myMiddleware);
app.route('/')
.get(function(req, res) {
handler.respond(req, res);
});
if (!module.parent) {
server.listen(PORT, function(err) {
if (err) {
logger.error(err);
return;
}
});
}
module.exports = app;
handler.js contains ..
var handler = {
respond: function(req, res) {
res.sendStatus(200);
}
};
module.exports = handler;
myModule.doStuff is implemented using ..
function doStuff(server) {
const SERVER = server;
return function (req, res, next) {
if (server.connections === 2) {
res.send({
message: 'Overloaded'
});
} else {
next();
}
}
}
I test the routes are setup using ..
describe('/', function() {
it('should test endpoint', function(done) {
sandbox.stub(handler, 'respond', function(request, response) {
response.send('called');
});
request(app).get('/')
.expect('called')
.end(done);
});
});
Is there a way that I can assert the middleware is actually attached
to the route in my unit test?
Well that question actually has two sides to it.
Testing that Express.js works as its supposed to
I would personally consider it a waste of time to test Express.js. It already has it's own test suite and it has been around for ages and therefore you should be able to trust that app.use() works as it is supposed to.
Testing that you are passing the expected middleware to app.use()
This is more relevant and you can lay the groundwork for being able to perform tests by structuring your code this way:
var myMiddleware = {
m1: {
path: 'somePath',
callback: 'someCallback'
},
m2: {
path: 'anotherPath',
callback: 'anotherCallback'
}
}
function mountMiddleware () {}
for (var middleware in myMiddleware) {
app.use(middleware.path, middleware.callback);
}
}
Now you can perform unit testing on the contents of myMiddleware and the workings of mountMiddleware() and thereby assert that all your middleware is correctly passed to app.use() (which you expect to work).
If you can change your middleware to something like this:
function doStuff(server) {
const SERVER = server;
return function (req, res, next) {
req.doStuffRun = true;
if (server.connections === 2) {
res.send({
message: 'Overloaded'
});
} else {
next();
}
}
}
Then you will be able to test for req.doStuffRun in your callbacks.
But here it doesn't seem that it is called because you are not running the actual request but you are calling the handler which does not contain the middleware.
I am not really sure what to title this, but I'm new to Node.js. I just found a neat REST API project on GitHub to implement but I'm not sure how I can split all GET and POST etc. to separate files.
I have one singular api.js file where I have
function API_ROUTER(router, connection, md5) {
var self = this;
self.handleRoutes(router, connection, md5);
}
API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
router.get("/", function(req, res) {
res.json({"Message" : "Hello World !"});
});
};
module.exports = API_ROUTER;
Now how can I create a sibling other.js and use:
var api = require('./api.js');
// Create router.get, router.post etc. here?
but I'm not sure how I can split all GET and POST etc. to separate files.
One way you can organize your routes would be to have a separate object for each route that has the handlers (separated by HTTP methods) and other needed info such as the path:
api/home.js
module.exports = {
path: '/',
handlers: {
'get': function(req, res) {
res.json({"Message" : "Hello World !"});
},
'post': {
// ...
}
// ...
}
}
api/other.js
module.exports = {
path: '/other',
handlers: {
'get': function(req, res) {
res.json({"Message" : "Other !"});
},
// ...
Then you can load all of these inside the handleRoutes method:
API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
var routes = ['home', 'other'];
routes.forEach(function(name) {
// load the current route object (NOTE: you should use the path module for determining file path in a cross-platform manner)
var routeObject = require('./' + name + '.js');
var apiPath = routeObject.path;
var handlers = routeObject.handlers;
var methods = Object.keys(handlers);
// assign handlers for each method
methods.forEach(function(method) {
router[method](apiPath, handlers[method]);
});
});
};
This will install all your routes with the appropriate information and handlers.
Now you can call this code by instantiating your API_ROUTER with the necessary data:
// initialize the api (and handle the routes internally)
var Api = new require('./api.js')(router, connection, md5);
If you implement a RESTful API, then you should keep in mind that this is just one way how you can provide data, and you might want to change it in future, as of that the API will most of the time only be a translation layer.
Normally you will split your code based on the resources, and the code that is handling the request won't have so much logic, it will just take the request and pass it to you internal API. For that purpose you not really need an additional layer if you already use express.js or a similar library.
In express the app.use([path,] function [, function...]), already provides the functionality you would need to modularize your code. For each resource your will create an own express.Router that itself also might mount another sub module. So for this part you do not really need a library.
When might a library be useful:
if it automatically translates thrown errors to the correct response codes
if it includes a tool to automatically create a documentation to your API
if it fully abstracts the underlaying routing system so that you can hook into express, hapi, ... without the need to change the code.
Here how a setup with express.js could look like
./lib/rest/customer.js
var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();
router.get('/:id', function(req, res, next) {
customerSystem.find({
id: req.params.id
}, function(err, customer) {
if (err) {
res.status( /*correct status code*/ ).send( /*depending on the api return json, xml, ....*/ )
} else {
res.send( /*depending on the api return json, xml, ....*/ )
}
})
});
router.delete('/:id', function(req, res, next) {
customerSystem.delete({
id: req.params.id
}, function(err) {
//...
});
});
router.post('/', function(req, res, next) {
//...
});
//save the customer id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
req.customerId = req.params.id;
next();
});
router.use('/:id/addresses', require('./customer-address') )
module.exports = router;
./lib/rest/customer-address.js
var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();
router.get('/:id', function(req, res, next) {
customerSystem.find({
id: req.customerId
}, function(err, customer) {
// ...
})
});
/* ..... */
//save the address id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
req.addressId = req.params.id;
next();
});
router.use('/:id/addresses', require('./customer-address') )
module.exports = router;
In express, everything else held constant, is there a difference between:
app.all('/', mongoProxy(config.mongo.dbUrl, config.mongo.apiKey));
and
app.all('/', function (req, res) {
mongoProxy(config.mongo.dbUrl, config.mongo.apiKey);
});
The former is able to return the return value from mongoProxy while the latter is not, where mongoProxy looks something like this:
module.exports = function(basePath, apiKey) {
basePath = url.parse(basePath);
// Map the request url to the mongolab url
// #Returns a parsed Url object
var mapUrl = module.exports.mapUrl = function(reqUrlString) {
//use the basePath to Parse the URL
return newUrl;
};
var mapRequest = module.exports.mapRequest = function(req) {
var newReq = mapUrl(req.url);
// Make a new request and return it..
return newReq;
};
var proxy = function(req, res, next) {
try {
var options = mapRequest(req);
// Create the request to the db
var dbReq = https.request(options, function(dbRes) {
// Save result
});
// { send result }
res.send(data);
res.end();
});
});
// send request
dbReq.end(JSON.stringify(req.body));
} catch (error) {
//..
}
};
return proxy;
};
The documentation is not clear on explaining the conceptual difference between the two; in the examples I've seen, the former function
app.all('/', mongoProxy(config.mongo.dbUrl, config.mongo.apiKey));
is able to access the req and res object without having it actually passed in as done in the latter, function (req, res).
What is the difference between the two, and is one preferable?
tl;dr
Yes, there is a difference: the first will work, whereas the second will hang (you don't invoke the anonymous function returned by mongoProxy). The first is preferable because it is more idiomatic to express (you're using middleware).
First, note how in mongoProxy, you return proxy, an anonymous function:
module.exports = function(basePath, apiKey) {
/* snip */
var proxy = function(req, res, next) { // <-- here
/* snip */
};
return proxy; // <-- and here
};
Let's break it down:
var proxy = mongoProxy(config.mongo.dbUrl, config.mongo.apiKey)
// proxy is an anonymous function which accepts: (req, res, next)
app.all('/', proxy);
// express will use proxy as the callback (middleware), which means this is the same as:
app.all('/', function (req, res, next) {
proxy(req, res, next)
})
Let's rewrite the second example—which should make clear why it doesn't work:
var proxy = mongoProxy(config.mongo.dbUrl, config.mongo.apiKey)
app.all('/', function (req, res) {
proxy // nothing happens because you don't invoke the function
});
If you want to use the second example, you could invoke proxy with proxy(req, res, next), but this is not idiomatic (in general and especially for express). Express is all about middleware, so use the first example.
Here's another example, which uses a closure (much like your mongoProxy function):
function getPermissionLevelMiddleware (level) {
// returns an anonymous function which verifies users based on `level`
return function (req, res, next) {
if (req.isAuthenticated() && req.user.permission.level > level)
return next()
return res.redirect('/no/permission')
}
}
var isAdmin = getPermissionLevelMiddleware(9000)
// `isAdmin` only allows users with more than 9000 `user.permission.level`
var isPleb = getPermissionLevelMiddleware(1)
// `isPleb` allows users with more than 1 `user.permission.level`
app.get('/admin', isAdmin, function (req, res) {
res.render('admin.jade')
})
Obviously the first one will return result because req and res objects are accessible to it, where as second case you need to send req and res in the method params of mongoProxy. If you won't send, req and res won't be accessible to it. So, for second scenario to work, the method signature need to be changed to :
module.exports = function(basePath, apiKey, req, res) {
I have done
I am trying to decorate render function in restify's router with this code...
decorate.js
module.exports = function (server) {
return function (req, res, next) {
function newRender(orig) {
return function(path, params, query) {
return "http://localhost:3000" + orig(path, params, query);
}
}
server.router.render = newRender(server.router.render);
next();
}
}
and in my server.js
var restify = require("restify");
var decorate = require("./decorate");
var server = restify.createServer();
server.pre(decorate(server));
server.get({name: "get_user", path: "/users/:id"}, function(req, res){
res.send(req.params.id);
});
server.get("/decorate", function(req, res){
res.send({data: server.router.render("get_user", {id: 2})});
});
server.listen(3000);
but I only get this error. Please help.
{"code":"InternalError","message":"Cannot read property 'get_user' of undefined"}
You are passing the original render method with global this as context. Just bind the server.router as context when passing it:
original_render = server.router.render;
function decorate(){
...
server.router.render = newRender(original_render.bind(server.router));
...
}
Update: You keep the reference of original render method outside the middleware function. Otherwise there will be a stack of newRender calls with increasing requests.