Express route not being recognized. Responds with 'Cannot GET' - javascript

app.js
var express = require("express");
var app = express();
var path = require('path');
var db = require('./db');
var bodyParser = require('body-parser');
app.listen(80);
app.set('view engine', 'jade');
app.set('views', "./views");
// app.get('/', _GetMainPage);
// app.get('/sites', _GetSites);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded({ extended: true })); // Support encoded bodies
app.use(bodyParser.json()); // Support json encoded bodies
app.use(require('./controllers'));
./controllers/index.js
var express = require('express');
var router = express.Router();
router.use('/', require('./sites'));
router.use('/site', require('./site'));
module.exports = router;
./controllers/sites.js
var express = require('express');
var router = express.Router();
var site = require('../models/site');
router.get('/', function(req, res) {
site.getAll(function(err, rows){
if(err) {
res.send(err);
return;
}
res.render('sites', { sites : rows });
});
});
./controllers/site.js
var express = require('express');
var router = express.Router();
var site = require('../models/site');
router.get('/site', function(req, res) {
// console.log("get /site received. req.body: " + req.body);
res.render('site', {
site: {
name : req.params.name
}
});
});
module.exports = router;
When I request localhost/site I get a response saying:
Cannot GET /site
localhost/ works perfectly
I have been looking at this for a while and can't find the problem yet. If there is anything I can add, let me know. Thanks.

Thank you to the person that commented with the answer:
What happens if you navigate to /site/site? Your site.js route is relative to the route you provided in use. So it should be router.get('/' ... not router.get('/site' ...
The ./controllers/site route is already being routed to /site. On top of this I was calling router.get('/site', ...). This means it was actually routing to /site/site.
The solution is to just use router.get('/', ...) in the site.js file instead.

This really helped me, thank you.
Basically, the root path in the sub-app is defined in your core app where you mount it via the app.use() method.
the best example I can find from app.mountpath docs is here:
https://expressjs.com/en/4x/api.html#express.router
The app.mountpath property contains one or more path patterns on which a sub-app was mounted.
var express = require('express');
var app = express(); // the main app
var admin = express(); // the sub app
admin.get('/', function (req, res) {
console.log(admin.mountpath); // /admin
res.send('Admin Homepage');
});
app.use('/admin', admin); // mount the sub app
It is similar to the baseUrl property of the req object, except
req.baseUrl returns the matched URL path, instead of the matched
patterns.
If a sub-app is mounted on multiple path patterns, app.mountpath
returns the list of patterns it is mounted on, as shown in the
following example.
var admin = express();
admin.get('/', function (req, res) {
console.log(admin.mountpath); // [ '/adm*n', '/manager' ]
res.send('Admin Homepage');
});
var secret = express();
secret.get('/', function (req, res) {
console.log(secret.mountpath); // /secr*t
res.send('Admin Secret');
});
admin.use('/secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager', on the parent app

Related

Routing keeps returning 404 instead of displaying other views besides index, users, and error in Express.JS

I am setting up a site on Express.JS with express-generator but ran into a hiccup with the routing. Currently I keep receiving the "error" view and a 404 message whenever sending a GET request to another route I set up ("/hook"). Currently the two routes that are working is "/" which goes to the "index" and "/users" which goes responds a message. I would like to see why I am getting this error as the others work.
Here is the app.js file:
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
var hookRouter = require("./routes/hook");
var app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/hook", hookRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// // error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// // render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
Here is the index router
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
Here is the hook router:
var express = require("express");
var router = express.Router();
/* GET hook page. */
router.get("/hook", function (req, res) {
res.send("Hook Page Works");
});
module.exports = router;
Please let me know there is any more info I can give. Thanks!
The hook router needs to be:
/* GET hook page. */
router.get("/", function (req, res) {
res.send("Hook Page Works");
});
This:
app.use("/hook", hookRouter);
has already used the /hook part of the path so within the router, you just want /.
Your original combination of:
app.use("/hook", hookRouter);
router.get("/hook", ...);
will respond to the URL /hook/hook.

Express subrouter returns 404

I have this router (http/api/ping.js):
var express = require('express');
var router = express.Router();
router.get('/ping', function (req, res) {
res.send("You called /api/ping");
});
module.exports = router;
This router is embedded into this router (http/api/index.js):
var express = require('express');
var router = express.Router();
router.get('/', function (req, res) {
res.send('You called /api');
});
router.use('/ping', require('./ping'));
module.exports = router;
And this router is used by my Express.js app (app.js):
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
var logger = require('./config').logger;
// Create app
var app = express();
var server = http.createServer(app)
var io = require('socket.io')(server);
// App config
app.use(bodyParser.json());
app.use('/api', require('./http/api'));
// Display requests on console
app.use(function (req, res, next) {
logger.trace(req.method, req._parsedUrl.href);
next()
});
module.exports = {
app: app,
server: server
};
When I run the app, /api returns You called /api, but /api/ping gives me a 404.
I am using Node 6.9.1 and Express ^4.14.0
I think order matters in this scenario. Try putting /ping above the / get route.
router.use('/ping', require('./ping'));
router.get('/', function (req, res) {
res.send('You called /api');
});
Also in your ping route you say the path to your route is /ping you also say it is /ping when you import it to the other router, which would make the path /api/ping/ping
change
router.get('/ping', function (req, res) {
res.send("You called /api/ping");
});
to
router.get('/', function (req, res) {
res.send("You called /api/ping");
});
I think your routing is incorrect on this line
router.use('/ping', require('./ping'));
this will point to http/api/ping/ping
it should be
router.use('/', require('./ping'));

Using a router with Express and Node.js

I'm new to Node.js. I've pulled some code from examples, but somehow I've broken something :).
At this time, in my app.js file, I have a line that I think wires up Express with Node.js. That line looks like this:
app.js
var routes = require('./routes/index');
// ...
app.get('/', routes.router);
Then, in ./routes/index.js I have the following:
routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page */
router.get('/', function(req, res) {
res.send('respond with a resource');
});
module.exports = router;
When I run this, I get the following error:
Error: Route.get() requires callback functions but got a [object Undefined]
at Route.(anonymous function) [as get]
I don't understand. What am I doing wrong?
Thanks!
app.js
var routes = require('./routes/index');
//var routes = require('./routes') --> this works
// ...
app.use('/', routes); //Using the router instance as a middleware , relative to '/'
routes/index.js
var express = require('express');
var router = express.Router(); // new instance of Router
/* GET home page */
router.get('/', function(req, res) {
res.send('respond with a resource');
});
module.exports = router; // You export the intance
UPDATE
if you want more than 1 route file
app.js
var routes = require('./routes')
app
.use("/user",routes.user)
.use("/other",routes.other)
routes/index.js
module.exports = {
user : require(./user),
other : require(./other)
}
routes/user.js
var router = require("express").Router()
router.get("/",function (req,res){
// GET /user
})
.post("/",function (req,res){
//POST /user
})
module.exports = router;
routes/other.js
var router = require("express").Router()
router.get("/",function (req,res){
// GET /other
})
.post("/",function (req,res){
//POST /other
})
module.exports = router;
An example of a basic server.js:
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.sendfile(__dirname + '/client/views/index.html');
});
app.listen(3000, function() {
console.log('Server running on localhost:3000');
});
Comparing, I believe you need to listen to the port. Also I think your res.send should be sending an actual file.
More documentation on Nodejs here:
https://nodejs.org/api/
Also found a related questions on SO:
Node Route.get() requires callback function but got a [object undefined]

Node.js Express export routes for organization?

Utilizing express.Router() for API calls to/from our application:
var express = require('express');
var app = express();
var router = express.Router();
router.use console.logs before every API call:
router.use(function(req, res, next) { // run for any & all requests
console.log("Connection to the API.."); // set up logging for every API call
next(); // ..to the next routes from here..
});
How do we export our routes to folder/routes.js and access them from our main app.js, where they are currently located:
router.route('/This') // on routes for /This
// post a new This (accessed by POST # http://localhost:8888/api/v1/This)
.post(function(req, res) {
// do stuff
});
router.route('/That') // on routes for /That
// post a new That (accessed by POST # http://localhost:8888/api/v1/That)
.post(function(req, res) {
// do stuff
});
...when we prefix every route with:
app.use('/api/v1', router); // all of the API routes are prefixed with '/api' version '/v1'
In your new routes module (eg in api/myroutes.js), export the module.
var express = require('express');
var router = express.Router();
router.use(function(req, res, next) {
console.log('Connection to the API..');
next();
});
router.route('/example')
.get(function(req, res) { });
.post(function(req, res) { });
module.exports = router;
Then you can require the module in your main server/app file:
var express = require('express');
var app = express();
var myRoutes = require('./api/myRoutes');
app.use('/api', myRoutes); //register the routes
In your app.js file you can have the following:
//api
app.use('/', require('./api'));
In the folder api you can have 'index.js` file, where you can write something like this:
var express = require('express');
var router = express.Router();
//API version 1
router.use('/api/v1', require('./v1'));
module.exports = router;
In the folder v1 file index.js something like this:
var express = require('express');
var router = express.Router();
router.use('/route1', require('./route1'));
router.use('/route2', require('./route2'));
module.exports = router;
File route1.js can have the following structure:
var express = require('express');
var router = express.Router();
router.route('/')
.get(getRouteHandler)
.post(postRouteHandler);
function getRouteHandler(req, res) {
//handle GET route here
}
function postRouteHandler(req, res) {
//handle POST route here
}
module.exports = router;
route2.js file can have the same structure.
I think this is very comfortable for developing the node project.

Dynamic routes with different functions in express js

I have loads of router.get functions in my code which I think, could be reduced to a single switch-case function. Here is what I have tried:
function handlerA(req, res) {}
function handlerB(req, res) {}
var routes = {
'/url-one': handlerA,
'/url-two': handlerB
}
router.get('/*', function(req, res) {
var url = req.url;
if (routes[url]) {
routes[url](req, res);
}
});
This works but also, significantly slows my application. Is there any other solution which would not hit the performance of my app?
Thanks
Is there a reason you don't want to use router.get functions? I would guess express.js is internally performing the same logic that you are doing anyway. You are just replacing get functions with handlers.
If you are using similar logic between multiple routes, that may be worth abstracting.
I usually go with a setup like this:
app.js
routes.js
api/
user/
index.js
user.controller.js
user.model.js
image/
index.js
image.controller.js
image.model.js
/api/user/index.js:
var express = require('express');
var controller = require('./user.controller');
var router = express.Router();
router.get('/', controller.index);
router.post('/', controller.create);
module.exports = router;
/api/user/user.controller.js:
var User = require('./user.model');
exports.index = function(req, res) {
// Show list of users
};
exports.create = function (req, res, next) {
// Create user
};
/routes.js:
module.exports = function(app) {
// Insert routes below
app.use('/api/users', require('./api/user'));
app.use('/api/images', require('./api/image'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
};
And lastly, the /app.js:
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var mongoose = require('mongoose');
var config = require('./config/environment');
// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options);
// Populate DB with sample data
if(config.seedDB) { require('./config/seed'); }
// Setup server
var app = express();
var server = require('http').createServer(app);
require('./config/express')(app);
require('./routes')(app);
// Start server
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
Most of this is directly from the Yeoman Generator Angular-Fullstack and it has a really nice setup!

Categories

Resources