Express app.all interfering with API calls - angularjs

I'm building a MEAN app and Angular is handling any routes that are defined by the client such as '/profile', '/stream' etc.
Because I'm using HTML5Mode in Angular, I've had to add the following to my express config to allow clean URLs to be accessed and input from browser URL bar:
app.all('/*', function (req, res, next) {
res.sendfile('views/dashboard.html', { root: __dirname });
});
This however is now interfering with my API and any API calls are returned blank, so for example if I visit users/active/profile which should return a JSON response of the current user's details, the browser redirects you to the homepage.

Express will handle the requests URLs(routes) in the order you declared them, since * is an exception to all other previous route declarations you need to move this code to the end of your routes:
/** this needs to be your last route **/
app.all('/*', function (req, res, next) {
res.sendfile('views/dashboard.html', { root: __dirname });
});

Related

Redirecting to static page when HTTP method is not found on Node backend

I have a single page app written in AngularJS and NodeJS. On the client side, there are several paths that the user can navigate to:
http://jabaridash.com/#!/home
http://jabaridash.com/#!/interests/travel
When the user types in a path that does not exist such as http://jabaridash.com/#!/foo, AngularJS handles it by rerouting to the /notFound path, and then that page redirects the user back to the home page. This is the code:
$urlRouterProvider.otherwise('/notFound');
This works when the path begins with #!/anyPath. However, if I were to type jabaridash.com/whatever, Angular does not reroute it. I am not sure if that has to do with the fact that I am using $stateProvider and modules to navigate, or I need to handle that type of path on the backend. I am assuming that I need to handle it on the Node side, because I do have one REST endpoint called photography setup on the NodeJS side, which can be accessed via jabaridash.com/photography (without #!). This endpoint works fine, but any other endpoint that I do not have setup will get a response of:
Cannot GET /something
This is to be expected, as there is no endpoint there. So essentially, how do i get NodeJS to redirect to my index.html. The way that I am serving the static page follows:
/**
* #description Set up the server
*
* #param dir directory to serve the index.html from
*/
function setupServer(dir) {
server.use(express.static(dir), function(req, res, next) {
// Allow cross origin from any host
res.setHeader('Access-Control-Allow-Origin', '*');
next();
});
// Set up the photography REST endpoint
photography_controller(server, dir);
}
My photography endpoint is setup as follows:
server.get('/photography', function(req, res) {
var searchPath = '/client/modules/interests/photography/img/thumbnail/';
// Send the list of files for use on client side
res.send(fileList(dir + searchPath, searchPath));
});
Is there a generic way to tell Node to say..."If the endpoint / HTTP method is not defined for a given path, redirect to a known path?"
This snippet below tells express to redirect to not-found when the path start with /example but has no specified handler in the router. Other routes that don't start with /example will not redirect because they won't be routed into the router in the first place.
const express = require('express');
const app = express();
// create a router for /example
var router = express.Router()
.get('/', function (req, res) {
res.send('example home');
})
.post('/about', function (req, res) {
res.send('About example');
})
/* catch all middleware for routes starting
with /example that redirects to /not-found */
.use(function (req, res, next) {
return res.redirect('/not-found');
});
// attach router
app.use('/example', router);
// create a not-found router handler
app.get('/not-found', function (req, res) {
res.send('Not found page');
});
app.listen(3000, () => console.log('App listening on port 3000'));
Right after your routes definition, do the following:
server.get('/photography', function(req, res) {
//do something
});
// catch 404 and forward to error handler
server.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//
// error handler
server.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
//render the page you want to navigate to. In this example, I navigate the user to google
res.redirect('http://google.com');
});

node redirect not working on angular

hi I'm new to node and I'm building a simple MEAN stack app, to reduce the code I'm sending front end files like this
app.use(express.static(path.join(__dirname, 'public')));
i have also build a simple middleware for simple authentication
requireLogin = function (req, res, next) {
if (!req.user) {
console.log('redirecting :)');
res.redirect('/');
} else {
next();
}
};
app.use('/rooms',requireLogin);
I'm trying to use this middleware on routes made in angular.
but this is not working when i navigate through my angular app (it works when i directly put the URL to the address bar) i have also removed the /#/ which is added by angular.
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
I'm using ui-router for routing.
You should do redirecting on angular, but not on node.js application. For example,
requireLogin = function (req, res, next) {
if (!req.user) {
console.log('User does not exist.');
return false;
//
} else {
next();
}
};
app.use('/rooms', requireLogin);
Then, /rooms won't be able to access unless there is user logged-in.
Backend routes (express ones): Those are the routes that an end user won't have to know about or even use them (your angular app will use them to communicate with the backend to work with its data but an end user wouldn't put them directly on the browser)).
Frontend routes (angular ones): Are the routes that maps to different pages of your application and because of that, end users can use them to access some parts of your application directly.
Read Express.js or angular for handling routes in a MEAN application? for more details.

Is it possible to route api calls in different files with angular?

I cant get my mind straight about routing of api calls with angularjs and express(ie nodejs). I set up the routing in my server as below:
require('./app/routes')(appExpress, passport);
I will have three collections in my database. I need to set upp calls to the api for all the collections in my routes file as below:
module.exports = function(app, passport) {
app.get('/api/compititions', function(req, res) {
Comps.find(function(err, comps) {
console.log(comps);
if (err)
res.send(err);
res.json(comps);
});
});
app.get('/api/swimers', function(req, res) {
// Add code to do something
});
app.post('/api/swimers', function(req, res) {
// Add code to do something
});
// all other calls
app.get('*', function(req, res) {
// send the rest of the calls to the app
});
}
The problem is that adding calls and code for 15 ish calls will become a very LONG file. I would like to separate these calls to different files or in some way make this file readable. Is that good practice or am I on the wrong path?
Thanks for the help and guidance!

NavBar address loading angular template but not root shell

I am using Node.JS with Express, Angular.JS and the node module connect-roles for ACL. I want to allow a user with user.status of "Platinum" to access "Platinum" but not "Gold" and vice versa.
I have the ACL part working, if I enter /Platinum into the navigation bar I can't access /Gold, but when I try to access /Platinum I only get the template but not the root shell, so what comes up is this:
You made it!
You have the {{status}} status!
If I click on a link in angular to /Platinum, everything works as it should. If I enter any neutral address in the navigation bar, everything works as it should.
This should be an easy fix, but I've not figured it out.
Here is the code that sets up authorizations, I'm pretty sure everything here is okay.
ConnectRoles = require('connect-roles')
var user = new ConnectRoles({
failureHandler: function(req, res, action){
var accept = req.headers.accept || '';
res.status(403);
if(accept.indexOf('html')) {
res.render('access-denied', {action: action});
} else {
res.send('Access Denied - You don\'t have permission to: ' + action);
}
}
});
var app = express();
app.use(user.middleware());
// Setting up user authorizations,
// i.e. if req.user.status = "Platinum", they are given Platinum status
user.use('Platinum', function(req) {
if (req.user.status == 'Platinum') {
return true;
}
});
user.use('Gold', function(req) {
if (req.user.status == 'Gold') {
return true;
}
});
user.use('Admin', function(req) {
if (req.user.status == 'Admin') {
return true;
}
});
That sets up authorizations, now the problem lies below with the routing.
app.post('/login', passport.authenticate('local',
{ successRedirect: '/', failureRedirect: '/login' }));
app.get('/Platinum', user.is('Platinum'), function(req, res) {
//Obviously the code below is wrong.
res.render('templates/support/Platinum');
});
app.get('/Gold', user.is('Gold'), function(req, res) {
res.render('templates/support/Gold');
});
The way you are configuring your routes on server side (using express) is not correct. For a single page app like AngularJS, you need to do all of the routing for pages on the client (i.e. in Angular). The server still defines routes for API requests (e.g. getting and posting data) and static resources (index.html, partial HTML files, images, javascript, fonts, etc), though.
Thus the following code is wrong in your server side JS:
app.get('/Platinum', user.is('Platinum'), function(req, res) {
//Obviously the code below is wrong.
res.render('templates/support/Platinum');
});
app.get('/Gold', user.is('Gold'), function(req, res) {
res.render('templates/support/Gold');
});
Just remove those lines.
Instead, you need to define the routes that the server will handle, such as your /login post one first, and how to get static files (I suggest prefixing them all with /pub in the URL). Then you need to do something like the technique in this answer to return your index.html page if no routes are matched.
That way, when a user types http://localhost:port/Gold, express will see there is no route defined for /Gold, so it will return index.html, which will load AngularJS, run your Angular app, which will then look at the URL and see if that matches any of the routes your AngularJS app has configured, and if so, fetch the partial for that page and insert it into your ng-view (if using the core router).

Unable to hit my local API route in Express

I have a server and client folder, inside my client folder I have 2 Angular apps /website and /dashboard
My current routing setup (just for development) going to / will load the website app and views and /dashboard loads the dashboard up:
//website api ==================================================================
var website = express.Router();
app.use('/', website);
app.use('/', express.static("../client/"));
console.log(__dirname + "../client/");
website.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
website.get('/', function(req, res) {
var path = 'index.html';
res.sendfile(path, { 'root': '../client/website/' });
});
//dashboard api ================================================================
var dashboard = express.Router();
app.use('/dashboard', dashboard);
dashboard.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
dashboard.get('/dashboard', function(req, res) {
var path = 'index.html';
res.sendfile(path, { 'root': '../client/dashboard/' });
});
// API to add new accounts:
app.post('/api/accounts/', accountsController.create);
In my dashboard app, the accounts controller I have the following $resource call:
var Account = $resource('/api/accounts');
Which is suppose to hit this API on my server main.js:
// API to add new accounts:
app.post('/api/accounts/', accountsController.create);
However currently getting a 404 on the call
'POST http://localhost:9999/api/accounts 404 (Not Found)'
I think it's the mismatch of trailing slash vs. no trailing slash between your angularjs code and your expressjs code. Try app.post('/api/accounts', accountsController.create);.

Resources