I'm making a single page app with Angular routes on the front end, but the backend is giving me grief.
All the routes that involve interfacing with the database work, but when I add in a route (Copying the exact same structure) to send an html file, or just hello world, it returns a 404, not even registering on the node console (with one weird exceptions noted below).
I read this post explaining how static should come after routes, it makes sense, but it's not working on my code.
app.js is as follows:
// SETUP
var express = require('express');
var app = express();
var router = express.Router();
var mongoose = require('mongoose');
var port = process.env.PORT || 3001;
var database = 'mongodb://example-database...';
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// CONFIG
mongoose.connect(database);
// Note: response parser must be placed before routing
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.set('jsonp callback name', 'cb');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(router);
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
next();
});
// ROUTES
require("./routes/api_chirp.js")(router);
require("./routes/api_video.js")(router);
require("./routes/api_interaction.js")(router);
require("./routes/api_user.js")(router);
require("./routes/api_search.js")(router);
require("./routes/api_jsonp.js")(router);
require("./routes/index.js")(router);
app.use(express.static(path.join(__dirname, 'public')));
// ERROR HANDLING
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
module.exports = app;
app.listen(port);
console.log("App listening on port " + port);
index.js (Note: The same structure used in other working API routes (using an alternative route, i.e. "/api/someroute")
module.exports = function(router) {
router.route('/workspace') // Only works if route is prefixed with "api_someword", "someword" itself won't work.
.get(function(req, res) {
console.log('request received');
res.send('hello world');
}); // Ends - Post
};
Question: I'm at the end of my rope... ANY suggestions, answers will help at this point. How do I get that route in index.js working?
// ROUTES
require("./routes/api_chirp.js")(router);
require("./routes/api_video.js")(router);
require("./routes/api_interaction.js")(router);
require("./routes/api_user.js")(router);
require("./routes/api_search.js")(router);
require("./routes/api_jsonp.js")(router);
require("./routes/index.js")(router);
pass the app object like this
// ROUTES
require("./routes/api_chirp.js")(app);
require("./routes/api_video.js")(app);
require("./routes/api_interaction.js")(app);
require("./routes/api_user.js")(app);
require("./routes/api_search.js")(app);
require("./routes/api_jsonp.js")(app);
require("./routes/index.js")(app);
Solved:
Another developer putting a path filter on nginx that prevented any url that didn't have isn't prefixed with /api to get through to node. I added it and it solved the problem.
Related
I am building a day planner, and while I was setting the routes I noticed I am receiving a 404 for every routes other than the main Home page route ie, index or "/".
This is app.js file
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 calendarRouter = require('./routes/calendar');
var app = express();
//Set up mongoose connection
var mongoose = require('mongoose');
var mongoDB = 'mongodb+srv://<user-name>:<password>#cluster0.3xw67.gcp.mongodb.net/<db-name>?retryWrites=true&w=majority';
mongoose.connect(mongoDB, { useNewUrlParser: true , useUnifiedTopology: true});
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
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('/calendar', calendarRouter);
// 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;
This is the calendar.js route
var express = require('express');
var router = express.Router();
var schedule_controller = require('../controllers/scheduleController');
router.get('/', schedule_controller.index);
router.get('/calendar/create', schedule_controller.schedule_create_get);
router.post('/calendar/create', schedule_controller.schedule_create_post);
router.get('/calendar/:id/delete', schedule_controller.schedule_delete_get);
router.post('/calendar/:id/delete', schedule_controller.schedule_delete_post);
router.get('/calendar/:id/update', schedule_controller.schedule_update_get);
router.post('/calendar/:id/update', schedule_controller.schedule_update_post);
router.get('/calendar/event/:id', schedule_controller.schedule_details);
router.get('/events', schedule_controller.schedule_list);
module.exports = router;
This is the index.js route, I did a redirect here!
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.redirect('/calendar');
});
module.exports = router;
And here is the Controller for the calendar.js route.
var Schedule = require('../models/schedule');
exports.index = function(req, res) {
res.send('NOT IMPLEMENTED: Site Home Page');
};
exports.schedule_list = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule List');
};
exports.schedule_details = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule Detail: ' + req.params.id);
};
exports.schedule_create_get = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule create GET');
};
exports.schedule_create_post = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule create POST');
};
exports.schedule_delete_get = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule delete GET');
};
exports.schedule_delete_post = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule delete POST');
};
exports.schedule_update_get = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule update GET');
};
exports.schedule_update_post = function(req, res) {
res.send('NOT IMPLEMENTED: Schedule update POST');
};
Okay I found the bug it was me using index url that is / which I redirected to /calendar. And I have been using the rest of the url routes without calling the redirected one ie, /calendar.
I tried calling the routes with /calendar/calendar and it works!
I don't yet know clearly how to explain this. I hope fellow stackoverflow'ers could explain why this is happening.
Here's me trying a noob explanation!
Redirecting index route / to another url route, changes the main url route of the website(address). So all the sub routes which is everything other than the index route should explicitly call the redirected route (new address). Because every-time we call the old address the redirection changes it to the new one. Making the old address a dead one.
(Humour : I would like to point out an example considering numbers. It's like whole numbers and natural numbers. Redirection is when the whole number changes to natural number.)
I have been spending hours trying to figure out why req.body is empty. I have looked everywhere on stackoverflow and tried everything but no luck.
Express.js POST req.body empty
Express req.body is empty in form submission
Express + Postman, req.body is empty
Express js req.body returns empty
I tried setting:
app.use(bodyParser.urlencoded({extended: false})); //false
but it did not change anything
Here is app.js
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 index = require('./routes/index');
var ajax = require('./routes/ajax');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.disable('etag'); //disable cache control
app.use('/', index);
app.use('/ajax', ajax);
// 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 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;
Now let's have a look at ajax.js
var express = require('express');
var router = express.Router();
router.post('/1/kyc/form', function (req, res, next) {
console.log(req.body) //prints {}
});
This is the request done by the client:
The Content-Type header of your request is invalid:
Content-Type: application/json;
The trailing semicolon shouldn't be there. So it should be this:
Content-Type: application/json
FWIW, it's not bodyParser.urlencoded that's being used here; because the body content is JSON, it's bodyParser.json that handles processing the request body. But it's perfectly okay to have both of these body parsers active.
EDIT: if what the client sends is beyond your control (or it's too much of a hassle to fix it client-side), you can add an additional middleware to Express that will fix the invalid header:
app.use(function(req, res, next) {
if (req.headers['content-type'] === 'application/json;') {
req.headers['content-type'] = 'application/json';
}
next();
});
Make sure that you do this before the line that loads bodyParser.json.
I'm trying out socket.io in my MEAN stack application by following a tutorial, but I don't know how to continue. I have the code below in one of my node.js routes. The plan is to connect with the socket, but for this I need the server variable. Does anyone know how to import this into my route file?
Movie-chat route file in Node.js
var express = require('express');
var router = express.Router();
var socket = require('socket.io');
var io = socket(server);
io.on('connection', function(socket){
console.log('made socket connection')
})
module.exports = router;
App.js
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 mongoose = require('mongoose');
var movieChatRoutes = require('./routes/movieChat');
var app = express();
mongoose.connect('mongodb://localhost:27017/moviemeter');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PATCH, DELETE, OPTIONS');
next();
});
app.use('/movieChat', movieChatRoutes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
res.render('index');
});
module.exports = app;
This is how they got it in the tutorial (by using app.listen())
I've looked through quite a bit of other posts and I'm very lost with this.
I can run a console.log(req) and get the following output
ServerResponse {
...
req:
IncomingMessage {
...
url: '/my-endpoint',
method: 'POST',
statusCode: null,
statusMessage: null,
...
body: { foo: 'bar' },
_body: true,
...
route: Route { path: '/my-endpoint', stack: [Object], methods: [Object] } },
...
Looks solid, so I would expect to do console.log(req.body) and get { foo: 'bar' } back in the console...but nope, getting undefined
After research, I found that it may be something with my app.js file and specifically with a body-parser, however, I have all of that already
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 http = require('http');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//Home Page Rendering
var index = require('./routes/index');
app.use('/', index);
// All other routes are kept in the `routes` module
require('./routes')(app);
module.exports = app;
routes.js
module.exports = function routing(app) {
var apiClient = require('./services/apiClient');
app.post('/get-device-info', function(err, req, res){
console.log("/get-device-info routes");
apiClient(req, res);
});
};
apiClient.js
module.exports = function callApi(req, res){
console.log(req);
console.log(req.body)
};
index.js
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's what I've tried
app.use(express.bodyParser());
Ensuring that the incoming request is explicitly declaring application/json
Declaring body parser.json in other ways
Adding a config function
Your problem is that Express doesn't use error first callbacks for its route handlers. The below code won't work because the app.post handler doesn't have the signature (req, res) => {}. In the below code err is equal to req, req is equal to res, and res is equal to next.
// routes.js
module.exports = function routing(app) {
var apiClient = require('./services/apiClient');
app.post('/get-device-info', function(err, req, res){
console.log("/get-device-info routes");
// Assuming the request is correct
// the value of body will be the request body
console.log(res.body)
apiClient(req, res);
});
};`
There are 3 different route callback signatures you can use in Express
(req, res) => {} - This is the most basic and defines a route that just cares about the request and response
(req, res, next) => {} - This is middleware callback signature which looks like a basic route callback but, it also assigns the next object which tells Express to call the next matching route.
(err, req, res, next) => {} - This is the error handling route callback and you only need 1 per Express Router Middleware or Express App. It gets called if next(err) is called within a Route or Middleware. More specifically, if next() isn't called with a string or nothing it will skip all remaining Middleware and Routes and go straight to the error handler. You can read more about it in the Express Docs
You'll need to change the route definition to
app.post('/get-device-info', (req, res) => {
apiClient(req, res)
})
Or you could even do this
module.exports = app => {
let apiClient = require('./services/apiClient')
app.post('/get-device-info', apiClient)
}
Try this, since it worked for me.
First declare app and then the bodyParser, since bodyParser is used within app:
const app = express();
const bodyParser = require('body-parser');
Then have these lines below:
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))
My angular2 app's routes don't work when accessed via URL... Express is rendering an error page instead.
So I have one route (/docs) which serves some static content and some other static resources, however, / is routed to an index.html which is managed by angular 2. So by opening the application root and then clicking various router links I can get to a route e.g. /tutorial/chapter/1. However, as that isn't a registered route in my express app, if I refresh the page I get a 404.
I want to be able to type http://localhost:3000/tutorial/chapter/1 into my browser and get that page. How do I set express to route all undefined routes to angular, and let angular handle the 404?
Here is my app.js:
var app = express();
// html view engine setup
app.set('views', path.join(__dirname, '/ng2/views'));
app.engine('html', require('jade').renderFile);
app.set('view engine', 'html');
app.use(express.static('ng2/views'));
app.use(express.static('ng2/public'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
// uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'ng2/public', 'favicon.png')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//all static assetes for hexo content
app.use('/docs', serveStatic('features/docs/public', { 'index': ['index.html', 'index.htm'] }));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
module.exports = app;
You can see the full repo here
Here is the routes middleware def:
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;
Angular 2 assumes that independent of the request URL, the frontend will be returned. This assumption is based on a feature modern browsers implement called push state. You have 3 options if you want to support anything but the bleeding edge of browsers:
Recommended: Seperate the API server from the client.
If you put your client on example.org and your express backend on api.example.org you can just do what Angular assumes to be true. You can also deploy independently and the client can live on a static host or CDN. This will require that you setup CORS though.
Catch-All Express Route
Make sure all your routes in Express differ from the ones you setup in NG2 and make a catch-all handler. Put something like this at the end of your routes/middleware but before the 404 handler!
app.use(function(req, res, next) {
res.sendFile("index.html");
})
Use legacy browser-url-styles for the router.
You can make the NG2 router use hashes for routes. Check here.
app.js
Since order is important and new code is inserted in multiple locations, the whole file is included. Look for comment started with // JS -
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 serveStatic = require('serve-static')
var file = require('./features/prepareTutorial');
var routes = require('./ng2/routes/index');
var app = express();
// html view engine setup
app.set('views', path.join(__dirname, '/ng2/views'));
app.engine('html', require('jade').renderFile);
app.set('view engine', 'html');
app.use(express.static('ng2/views'));
app.use(express.static('ng2/public'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
app.use('/persist', express.static(__dirname + '/persist'));
// JS - Add /app
app.use('/app', express.static(__dirname + '/ng2/views/app'));
// I have to comment this line because it failed
//file.processTutorial(); //generate html rendered patches for tutorial steps
//file.genGit(); //generate git SHA
file.processChapters();
// uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'ng2/public', 'favicon.png')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//all static assetes for hexo content
app.use('/docs', serveStatic('features/docs/public', { 'index': ['index.html', 'index.htm'] }));
//app.use(subdomain('docs', express.static('docs/public')));
app.use('/script', serveStatic('features/docs/public/script'));
app.use('/style', serveStatic('features/docs/public/style'));
app.use('/images', serveStatic('features/docs/public/images'));
app.use('/diff', serveStatic('features/tutorial/diffs'));
app.use('/git', serveStatic('features/git'));
app.use('/chapter', serveStatic('ng2/views/app/tutorial/chapter/chapters'));
app.use('/img', serveStatic('features/docs/source/img'));
app.use('/config', serveStatic('ng2/config'));
app.use('/', routes);
// JS - /tutorial static
//app.use('/tutorial', express.static('ng2/views/app/tutorial'));
// JS - /tutorial/chapter/* send index file
app.all(/^\/tutorial$/, (req, res) => {
res.redirect('/tutorial/');
});
app.use('/tutorial/', (req, res) => {
res.sendFile(__dirname + '/ng2/views/index.html');
});
// 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: {}
});
});
module.exports = app;
ng2/config/systemjs.config.js & ng2/public/config/systemjs.config.js
Use absolute path
This is the main issue. With relative path, the browser is requesting files at tutorial/chapter/2/app/*, tutorial/chapter/2/node_modules/*, etc, and the app break down completely.
// snip ...
var map = {
'app': '/app', // 'dist',
'#angular': '/node_modules/#angular',
'angular2-in-memory-web-api': '/node_modules/angular2-in-memory-web-api',
'rxjs': '/node_modules/rxjs'
};
// snip ...
ng2/views/index.html
Use absolute path
This won't stop the page from loading but a mess.
// snip ...
<link rel="stylesheet" href="/stylesheets/style.css">
// snip ...
Instead of app.use('/', routes);, register a middleware that will always serve the index.html. Be cautious though, this can cause your app to return index.html even inside the /docs route.
Just use the middleware that renders the index page:
app.use(routes);
Make sure the routes middleware itself always renders the page, not only on / path.
var express = require('express');
/* render home page. */
var router = function(req, res, next) {
res.render('index', { title: 'Express' });
};
module.exports = router;
Remove this the 404 handler (it should be automatic)
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
And change the node_modules route to the following (because SystemJS relies on 404 responses during resolution):
var modules = express.Router();
modules.use(express.static(__dirname + '/node_modules'));
modules.use(function(req, res, next) {
// Missing files inside node_modules must return 404
// for the module loader to work
res.sendStatus(404);
});
app.use('/node_modules', modules);