How to handle "Cannot <METHOD> <ROUTE>" in Express? - javascript

As a minimal example, consider following code:
var express = require('express');
var bodyparser = require('body-parser');
var app = express();
app.use(bodyparser.json());
app.use(errorhandler);
function errorhandler(err, req, res, next) {
res.setHeader('Content-Length', 0);
res.status(500).end();
}
app.post('/example', function(req, res) {
res.setHeader('Content-Length', 0);
res.status(200).end();
});
var server = app.listen(3000, function() {
console.log('server listening on http://%s:%s ...', server.address().address, server.address().port);
});
When I, for example, now try a PUT on /example, I get a Cannot PUT /example message with 404 status code. The same is true for all other routes and methods I did not declare. My error handler is only getting called on actual errors within a route or the body parser itself.
Is there a way to handle them by myself? I am using Express4.

Define a general handler with no route after all other use/get/post/etc:
app.use(function(req, res, next){
res.status(404);
res.render(...);
}

Related

Express use function

The below code not functioning as expected
var express = require('express');
var app = express();
app.use(function(req, res, next) {
console.log('first text');
next();
}, function (req, res, next) {
console.log('secondText');
res.end()
}).listen(3000)
app.use([path,] function [, function...])
Mounts the specified middleware function or functions at the specified path. If path is not specified, it defaults to '/' in express documentation but I can't run the second function, not sure why. When I try localhost:3000 in Firefox I receive Cannot GET /
This code is working, but previously it wasn't working:
var express = require('express');
var app = express();
app.use(function(req, res, next) {
console.log("one");
next();
})
.use(function(req,res,next){
console.log("second");
res.end()
})
.listen(3000)
Could it be because of the missing .?
var express = require('express');
var app = express();
app.use(function(req, res, next) {
console.log('first text');
next();
}, function (req, res, next) {
console.log('secondText');
}).listen(3000) //Was missing a period

Node, how can I send response headers on a node/express app?

I have a basic server. One of my tests that I need to pass is to send the response header of 200. I added the code for the server as it is now. But not sure how to send response headers. Thanks for any help you may be able to provide!
var express = require('express');
var bodyParser = require('body-parser');
var Users = require('./models/users');
var app = express();
app.use(bodyParser.json());
// YOUR CODE BELOW
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var router = express.Router();
// middleware for all requests:
router.use(function(req, res, next){
console.log('we out here babay!');
// get to the next route and ensures we don't stop here.
next();
})
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
app.use('/api', router);
// Do not touch this invocation of the `listen` method
app.listen('8888', function () {
console.log('listening on 8888');
});
// Do not touch the exports object
module.exports = app;
Use res.status(CODE) method!
res.status(200).json({ message: 'hooray! welcome to our api!' });
As highlighted in comments by jfriend00, default status code is 200 so any regular response will already be 200 but for other codes like 500 or 404, if your client side is considering it while reading the response, you can use res.status() method.

Routes issue in Express 4

Noob - trying to set up CRUD using routes on Express4 and Node. I've got the following GET and POST routes working ok, but DELETE and PUT are giving 404, Not Found errors, which is strange.
I'm using Postman for Chrome and have set the Content Type to application/json, and this is working ok - i do notice that on the DELETE and PUT queries the header still notes that it's sending as text/html, rather than JSON, although I've set both the RAW settings to JSON, and the Headers content type manually to application/json.
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Todo = require('../models/Todo.js');
/* GET /todos listing. THIS IS WORKING*/
router.get('/', function(req, res, next) {
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
/* POST /todos listings THIS IS WORKING*/
router.post('/', function(req, res, next){
Todo.create(req.body, function(err, post){
if (err) return next(err);
res.json(post);
});
});
/* GET /todos/id THIS IS WORKING*/
router.get('/:id', function(req, res, next) {
Todo.findById(req.params.id, function (err, post) {
if (err) return next(err);
res.json(post);
});
});
/* DELETE /todos/:id NOT WORKING*/
router.delete('/:id', function(req, res, next) {
console.log(req);
Todo.findByIdAndRemove(req.params.id, req.body, function (err, post) {
if (err) return next(err);
res.json(post);
});
});
module.exports = router;
Also this is a routes.js script that is being imported into app.js (see below):
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var todos = require('./routes/todos');
// set our port
var port = process.env.PORT || 3000;
//Requires the mongoose connection
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todoApp', function(err) {
if(err) {
console.log('connection error', err);
} else {
console.log('connection successful');
}
});
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/todos', todos);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
// start app ===============================================
// startup our app at http://localhost:3080
app.listen(port);
// shoutout to the user
console.log('Magic happens on port ' + port);
module.exports = app;
I looked into your implementation, it looks fine. Just one chance where i feel it can go wrong is, if we look into the documentation of Model.findOneAndRemove(conditions, [options], [callback]), you are going wrong in [options].
In [options] we can do :
sort: if multiple docs are found by the conditions, sets the sort
order to choose which doc to update
select: sets the document fields to return
Try this, i hope it will solve your problem.
You mentioned that, PUT is also having same 404 issue, could you please update your post by including same. Let's understand where it is going wrong.
There's a couple of things you might want to check.
Your POST is working as intended, but your DELETEs and your PUTs aren't. You've set the content type to application/json.
Given that you are using Express 4, and had to include a body parser yourself, do you happen to include the following lines?
var app = express();
// you probably have this, for application/x-www-form-urlencoded
app.use(bodyParser.urlencoded());
// extrapolating here, you only mentioned you were receiving 404s.
// you might be missing the following line?
app.use(bodyParser.json());
In your delete route, you log the response object, is this a typo? A more useful log would be of the request object - so you can determine what exactly the route thinks you sent.
Shot in the dark, but in the absence of additional information, I hope at least one of the answers are correct.

express (4.0) custom middleware runs on both instances of router even though it's only declared for one

I'm using the code below to learn a bit about the new express.js (4.0). I can't seem to understand why the logging is happening regardless of which path I hit with my browser. Shouldn't it only log for website.get and not for api.get paths?
// Express 4.0 test...
var express = require('express');
var app = express();
var website = express.Router();
var api = express.Router();
var port = process.env.PORT || 3000;
website.use(function (req, res, next) {
console.log(req.method, req.url);
next();
});
website.get('/', function (req, res) {
res.send('Home page');
});
website.get('/about', function (req, res) {
res.send('About page');
});
api.get('/', function (req, res) {
res.send({'json':'response'});
});
api.get('/user', function (req, res) {
res.send({'user':'john'});
});
// app.get('/', function (request, response) {
// response.writeHead(200, {"Content-Type": "text/html"});
// response.end("<h1>Hello, World!</h1>");
// });
app.use('/', website);
app.use('/api', api);
app.listen(port);
console.log('http(s) server revved up on port ' + port);
Any help would rock!
Update: I see, because '/api' matches '/', website gets applied to all routes. Is there any way to avoid this?
probably define the /api router first and the other one - second.
app.use('/api', api);
app.use('/', website);

Using different router for different subdomains in node.js with express

I want to use different routes in my app, depending on the subdomain in req.headers.host.
So I came around with this idea (extremely simplified example):
var express = require('express');
var domain1 = require('./routes/domain1');
var domain2 = require('./routes/domain2');
var app = express();
app.use('*', domainRouting);
function domainRouting(req, res, next){
var subdomain = req.headers.host.split('.')[0];
if(subdomain === 'domain1'){
app.use(domain1);
}
else{
app.use(domain2);
}
next();
}
//404 handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
res.send('error');
});
var server = app.listen(3001, function() {
console.log('Listening on port %d', server.address().port);
});
domain1.js:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('DOMAIN 1: ' + req.url);
});
module.exports = router;
domain2.js:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('DOMAIN 2: ' + req.url);
});
module.exports = router;
But this does not work, the routes are ignored and the request jumps into the last 404-handler.
Any ideas for this?
You can't use app.use() dynamically like that within a middleware. You might call your router directly with domain1(req, res, next) instead of app.use(domain1).
Or you might look into using a module like subdomain to make it easier to handle subdomains in Express.

Categories