Ok, this should be easy for somebody to point out.
I checked the other similar questions and none helped.
I'm trying to move all my routes to a separate routes.js file. In it I have:
module.exports = function (app) {
var user = {
list : require('./routes/user.js')
}
, index = {
index : require('./routes/index.js')
}
app.get('/', function(request, response){
response.send('You made it to the home page.')
});
app.get('/users', user.list);
}
And in my app.js file I have this:
var register_routes = require('./routes.js')
register_routes(app)
My index route works fine, but it kicks back on app.get('/users', user.list); with this error:
.get() requires callback functions but got a [object Object]
This is an out of the box express app so theres not too much to describe.
Thanks.
EDIT: Per request, here is what is in ./routes/user.js :
exports.list = function(req, res){
res.send("respond with a resource");
};
You export an object with the key list having the your function as value.
So to access your function you would need to do this require('./routes/user.js').list
Or with your code user.list.list.
To solve this you have two possibilities.
Either write:
var user = {
list : require('./routes/user.js').list
}
Or:
module.exports = function(req, res){
res.send("respond with a resource");
};
EDIT
If your routes/user.js will probably later look like this:
module.exports.list = function(req, res){
res.send("respond with a resource");
};
module.exports.delete = function(req, res){
res.send("delete user");
};
If yes then you can just write it that way in your routes.js:
var user = require('./routes/user.js');
I think what you want is:
module.exports = function (app) {
var user = {
list : function(request, response){
require('./routes/user.js');
}
}
}
, index = {
index : function(request, response){
require('./routes/index.js')
}
}
app.get('/', function(request, response){
response.send('You made it to the home page.')
});
app.get('/users', user.list);
}
In this way give a callback to the route and this callback execute the require.
If you are using router in your application for all routing purpose,
var express = require('express');
var router = express.Router();
var index = require('./index');
/* GET home page. */
router.get('/', index.list);
module.exports = router;
then in your index.js file, just do
router.list = function(req, res){
res.send("respond with a resource");
};
After so many time seeking around in web, I found something.
First of all, You instantiate the code like this on another file, (e.g.: humancomms.ts):
import express from 'express';
export function shout(request: express.Request, response: express.Response, next: () => void) {
response.send('Shout so loud!');
}
export function speak(request: express.Request, response: express.Response, next: () => void) {
response.send('Speak less loud!');
}
What exactly this code does? Nobody knows.(Hehe, just kiddin')
This make a middleware functions to separate from main server file to... organize, of course.
And how We can use it? Just like this (inside your server file):
const shout = require('./humancomms').shout;
const speak = require('./humancomms').speak;
app.use('/shout', shout);
app.use('/speak', speak);
This code takes all middlewares funcs and executes when some path is called.
This not solve all problems like multi path to same type, as if You want call differently intensities of shout ('/shout/high?asd=asd', '/shout/low?asd=asd'), but there is a catch You can try on secondary file:
import express from 'express';
export function shout(request: express.Request, response: express.Response, next: () => void) {
if (request.path.includes('/high')) {
response.send('Shout so loud!');
} else if (request.path.includes('/low')) {
response.send('Really shout?');
}
}
Look at this good article about:
TypeScript Express tutorial #1. Middleware, routing, and controllers (https://wanago.io/2018/12/03/typescript-express-tutorial-routing-controllers-middleware/)
and the official documentation website:
Writing middleware for use in Express apps (http://expressjs.com/en/guide/writing-middleware.html)
Related
I have the following case:
There is a list of routes in the form
var lst = ["route1/:foo", "route2/:bar", "route3/:bar/route4/:baz", ..] // this list has like 200 entries
I have the following code
app.use(lst, function (req, res) {
// here I want to know which route the middleware was invoked on
// req.route.path doesn't work unless I use app.METHOD()
// req.originalUrl would give me route1/200, instead of route1/:foo
})
What I tried so far:
Using the router stack as in app._router.stack, my routes aren't even registered there - I don't see route1/:foo, route2/:bar and route3/:bar/route4/:baz
Hook into the express router:
var Route = express.Route;
let defaultImplementation = Route.prototype.dispatch;
function foo(req, res) {
console.log('Called route ', req.route.path); // still doesn't trigger on the routes in lst, only parent routes
}
Route.prototype.dispatch = function handle(req, res, next) {
foo(req, res); // req.route is available here
defaultImplementation.call(this, req, res, next);
};
By the way, I'm passing those routes and using them along with http-proxy-middleware https://github.com/chimurai/http-proxy-middleware, so if you have any clues on how do achieve that with that library as well, I'd be very grateful as I couldn't find out.
I'm very new to express / NodeJS in general. I started to write a little application, providing a REST API. The whole thing should work like this:
the request gets routed (routes.js)
in routes.js, a function in a controller gets called
since my controller contains the app's logic, it should return data that gets sent with res.json(CONTROLLER_FUNCTION()).
My code:
controller.js
User = require('../models/user')
module.exports.users = function users() {
users = User.findAll().then(users => {
return users;
});
}
routes.js
/* GET users listing. */
router.get('/', function (req, res, next) {
res.json(userController.users())
});
So when my route gets called, nothing happens. I believe that happens because my controller logic is async. Probably I have to implement something like a wrapper/callback function (?)
So basically my question is: what is the "right" way to handle a situation like this? How should my code look like?
Example:
What I normally would do is to pass to userController.users a function, that gets called when the async action is done (.then).
routes.js
/* GET users listing. */
router.get('/', function (req, res, next) {
userController.users((data) => res.json(data));
});
controller.js
User = require('../models/user')
module.exports.users = function users(send) {
users = User.findAll().then(users => {
send(users);
});
}
Is this the best way to do this? / Is this considered good practice? Is it even recommended to not put my code directly into routes.js?
module.exports.getUsers = async () => {
const users = await User.findAll();
return users;
}
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;
I'm having an issue getting Sinon's stub to work correctly for me. When I stub list on retro and the test runs, app.get('/retro', retro.list) is executing the original function retro.list instead of the stub. Since this happens, the test fails because the stub's callCount is 0.
I'm more familiar with coffeescript and I have stubbed things in the same way. Is there something I'm not understanding about Javascript's scoping, or how the require('../routes/retro') works, or is retro is not the same in app.js and test.js.
Much thanks for the help and code below.
test.js:
var request = require('supertest')
, retro = require('../routes/retro')
, app = require('../app')
, sinon = require('sinon');
require('should');
describe('GET /retro', function() {
// less involved, but maybe stupid to test
it('should call retro.list', function(done) {
var stub = sinon.stub(retro, 'list');
request(app)
.get('/retro')
.end(function(err, res){
stub.callCount.should.equal(1);
if (err) return done(err);
done();
})
})
})
app.js:
var express = require('express')
, config = require('./config')
, routes = require('./routes')
, retro = require('./routes/retro');
var app = express();
config(app);
app.get('/', routes.index);
app.get('/retro', retro.list);
module.exports = app;
retro.js:
var retro = {
list: function(req, res){
console.log('actual called');
res.send("respond with a resource");
}
}
module.exports = retro;
You'll likely need to create your stubs before requiring/creating the app.
var request = require('supertest')
, sinon = require('sinon')
, retro = require('../routes/retro');
var stubRetroList = sinon.stub(retro, 'list');
var app = require('../app');
// ...
stubRetroList.callCount.should.equal(1);
This allows retro.list to be updated before it's passed to the route:
app.get('/retro', retro.list);
The issue is probably because retro.list isn't being passed-by-reference (pointer), but is rather a reference that's passed-by-value (copied). So, though sinon.stub() is altering retro.list, it wouldn't affect the copy that the '/retro' route already had.
I faced the same issue and the accepted answer (while true) was of no help. Turns out in order for sinon stubbing to work the stubbed method cannot be used in the same module. In other words stubbing a module endpoint will only stub the module endpoint and not the internal usage of the function referenced by module.exports.
Explained via an example:
module.js
const express = require('express')
const router = express.Router()
router.get('/', function (req, res) {
res.status(200).json(list())
})
function list() {
return ['something']
}
module.exports = {
router: router,
list: list
}
module.spec.js
// This stub will not work
sinon.stub(module, 'list').callsFake(() => ['something else'])
To make it work you have separate what you want to stub into its own module and use it that way:
sub_module.js
function list() {
return ['something']
}
module.exports = {
list: list
}
Now sub_module.list() can be stubbed.
(OP defines a method in place so this is not an issue for him)
I am a newbie in Node.js (and Express) and I am trying to make sense of this. Say I have a website with 3 pages (can be GET or POST): /, /page1, /page2. What should I do so that every page is handled by a separate JS file?
app.all('/', function(request, response)
{
// Get home.js to handle this request and response
});
app.all('/page1', function(request, response)
{
// Get page1.js to handle this request and response
});
app.all('/page2', function(request, response)
{
// Get page2.js to handle this request and response
});
Better yet, is there a way to define a wildcard so there is not so much repetition? Something like this:
app.all('*', function(request, response)
{
// Get *.js to handle this request and response. * is whatever the URI string is
});
The trick here is that app is local to the file that creates it. So you have to get that object to the scope of the other files.
Each other file should export a funciton that you can pass your app instance to so it can register new routes. An approach like this should work.
// home.js
exports.register = function(app) {
app.all('/', function(request, response) { ... });
};
// page1.js
exports.register = function(app) {
app.all('/page1', function(request, response) { ... });
};
// page2.js
exports.register = function(app) {
app.all('/page2', function(request, response) { ... });
};
//server.js - setup the app
app = express.createServer();
require('./home').register(app);
require('./page1').register(app);
require('./page2').register(app);
And for the second part of your question, you want to share some setup methods?
app.all('*', function(req, res, next) {
res.header 'x-snazzy-header', 'Im so snazzy'
next()
});
app.all('/page/:id', function(req, res) {
res.send('content for page #'+ req.params('id'));
});
First, you can use * or named params like /users/:id, to match a range of routes. And if you want to do some common setup, you can actually execute 2 routes. The route handler takes an optional third argument next. When invoked, it will try to find the next route to match. So you can setup things like common headers for a bunch of routes with it.
Continuing my discussion with #Alex. Here's how I did it. Any gotcha?
// app.js
var EXPRESS = require('express');
var URL = require('url');
var PATH = require('path');
var app = EXPRESS.createServer();
app.all(/^\/([a-zA-Z0-9-]+)$/, function(request, response, next)
{
var page = request.params[0];
if (PATH.existsSync(__dirname + '/' + page + '.js'))
{
require('./' + page).handleRequest(request, response, next);
}
else
{
next();
}
});
app.all('*', function(request, response)
{
response.send('Catch all');
});
// --- truncated for brievity
// page1.js
exports.handleRequest = function(request, response, next)
{
response.send('Howdy!');
};