Basic Express Routes puzzle - javascript

I got stuck in Mozilla js tutorial and need help. Here are excerpts from 3 files:
a)
the 2 pieces from app.js file show where to find Router handlers and then where to present them (my guess)
//app.js
//the following 3 vars do sit in routes folder, code copy-pasted var 3 my addition
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var coolRouter = require('./routes/cool');
var app = express();
....
//the following 2 'use' work just fine, the third sends err 404, 'not found'
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/users/cool', coolRouter);
b) part of the users.js sitting in routes folder:
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
c) part of the cool.js copied from the previous and sitting in routes folder:
/* GET cool text. */
router.get('/', function(req, res, next) {
res.send('you are cool, kid!');
});
I'd like to get it why it does not work.

The reason you cannot reach /users/cool is that your request is being cathed by the /users endpoint.
In order for your code to work as you intend it to do, you will have to place your routes like this:
app.use('/', indexRouter);
app.use('/users/cool', coolRouter);
app.use('/users', usersRouter);
With the /users/cool endpoint before the /users endpoint. That way, the request to /users/cool will not be catched by another endpoint.

Related

Express.js Routing is not making sense

I'm working on an Express.js app and I think I am having trouble understanding the nuances of multi-layer routing. My app has the following segment of code in its app.js file:
//app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
//new stuff
const routes = require('./routes');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// middleware functions required
app.use(logger('dev')); //handles logging
app.use(express.json()); //JSON payload parser
app.use(express.urlencoded({ extended: false })); //urlencoded payload parser
app.use(cookieParser());
//content routes
app.use('/jquery', express.static(__dirname + '/node_modules/jquery/dist/'));
app.use('/', express.static(path.join(__dirname, 'public'))); //static files (css and other js files)
app.use('/', routes); //everything else (see /routes/index.js)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
.
.
.
As indicated in the code, after a bunch of static file and default middleware setup for logging and such, app.use('/', routes); is declared, handing off to an index.js file in the /routes folder as follows:
//index.js
//main router entry point, sets up all route modules
//instantiate the express.Router class
const express = require('express');
const router = express.Router();
//import our route modules
const indexRouter = require('./indexRouter');
const resetRouter = require('./resetRouter');
const enrollRouter = require('./enrollRouter');
//map individual route modules to their respective routes
router.use('/', indexRouter);
router.use('/reset', resetRouter);
router.use('/enroll(/*)?', enrollRouter);
module.exports = router;
The three router.use lines call individual route files in the same directory as shown. The first two are simple get routes. The third one (router.use('/enroll(/*)?', enrollRouter);) has both get and post components via the enrollRouter.js file as follows:
//enrollRouter.js
const express = require('express');
const router = express.Router();
const { getEnroller } = require('../controllers/enrollGetController');
const { postEnrollment } = require('../controllers/enrollPostController');
router.post(/^(\/enroll\/new)/i, postEnrollment);
//router.post('/', postEnrollment);
router.get('/', getEnroller);
module.exports = router;
Here's where things get interesting. I'm using postman to make a post request to "/route/new". If the route string for the post route in the code above is set to '/', everything works fine, and enrollPostController.js is called returning appropriate content. However, if I set the route string to '/enroll/new' instead (the path I'm calling... doesn't matter if it's a string or a regex), the 404 error code in app.js is called.
I'm not following what is going on. I'm under the impression that the string at the beginning of a router.get or router.post call represents the path to be matched for the callback defined as the next parameter. When the path is clearly the one specified, why am I getting a 404?
The way I'm thinking, when the /enroll/new post request comes in, app.js should hand off to index.js for all routes matching '/'. Then index.js should hand off to enrollRouter because the route matches '/enroll(/*)?'. And then finally, enrollRouter.js should call postEnrollment defined over in ../controllers/enrollPostController, because the route matches '/enroll/new'. But it doesn't work that way.
Can someone enlighten? or fill in the holes in my understanding?
Here's the code in enrollPostController.js
//enrollPostController.js
module.exports = {
postEnrollment(erq, res) {
//at this point we have the form submission data.
console.log(erq.body);
res.send("received form submission!");
},
};
Try the following:
routes/index.js
// Delegate "/enroll/*" to router
router.use('/enroll', enrollRouter);
routes/enrollRouter.js
// Handle POST requests to "/enroll/new"
router.post('/new', postEnrollment);
I hope this helps.
If you are following some pattern and only endpoints are getting changed for example
http://localhost:4000/mycode/testUrl/abc
http://localhost:4000/mycode/testUrl/Pqr/xyz
http://localhost:4000/mycode/testUrl/abc/xyz/pqs
const service = express.Router();
// **console** is just to check your endUrl. you can print originalUrl as well
service.get('/*', function(req, res) {console.log(req.url); }
service.post('/*', function(req, res) { console.log(req.url);}
app.use('/mycode/testUrl', service);
In your index.js
The express router defined as
router.use('/enroll(/*)?', enrollRouter);
passes the '/enroll/new' to your enrollRouter.js
so all you need to give the "/" in the post route, so the "/enroll/new" is right in front of it but due to nesting of routes we can separate them.
Hope I answered the question.

A routing problem with workbox vuejs in production and express

I am creating a forum application to learn about VueRouter in Express. What I am trying to do is create a routing in vuejs and then take it to production. When I compile everything works fine. The view files go directly to the public folder in express and work almost perfect. I can change the route perfectly but when I touch CTRL + F5 from a different route to the main one, it returns a GET error.
For example this is my index and work perfect:
I can even change the route:
I touch F5 and reload the page without any problem, but when I touch CTRL + F5 to make the request again, obviously it returns an error because I don't have the route declared in express,
but vuejs returns only one html index as a view, I can't render any other files because they don't exist.
These public folder at image are the files created by vue by the build command:
This is my express configuration:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersNotifications = require('./routes/notifications');
var usersNotifications = require('./routes/notifications');
var app = express();
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('/notifications', usersNotifications);
module.exports = app;
this is my index route on express:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
The only option I have is to render the only index that vuejs offers. How can i Fix that?
The other problem is that I would not like these console workbox messages, how can i remove them so they never appear:
and this is the vuejs registerServiceWorkers.js file:
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
/***
* Note that here were some methods also display messages
* on the console and I deleted them. Methods like
*/
})
}
Any ideas?
Since vue router is handling page routing, you'll have to render index for all requested paths like:
router.get('*', function(req, res, next) {
res.render('index');
});
// in server
app.use('*', indexRouter);
If you're exposing other endpoints from server you'll have to mount this as the last route middleware like, say in your case:
app.use('/notifications', usersNotifications);
app.use('*', indexRouter);

Using multiple router defined in their own files in express

I am new to Node.js and express framework. I am getting an error when I am trying to go to the signuplogin route from my homepage route. I have also tried all the similar questions in the stackoveflow, but none of them have worked for me, so I thought of posting my own.
This is my app.js
var homepage = require('./routes/homepage');
var signupLogin = require('./routes/signuplogin');
var app = express();
app.use("/", homepage);
app.use("/signup-login", signupLogin);
This is my homepage.js in routes directory
var express = require('express');
var homepageRouter = express.Router();
/* GET Homepage. */
homepageRouter.get("/", function(req, res, next) {
res.render('../views/homepage/homepage.hbs');
});
module.exports = homepageRouter;
This is my signup-login.js in routes directory
var express = require('express');
var signupLoginRouter = express.Router();
/* GET Signup Login Page. */
signupLoginRouter.get("/signup-login", function(req, res, next) {
res.send('respond with a resource');
});
module.exports = signupLoginRouter;
Well my "/" route works perfectly but it says 404 when I try to access "/signup-login" route.
I also changed the route to "/signuplogin" because I thought maybe it doesn't except the "-" character in the route. But that didn't work as well. Any solution/advice?
You have done a mistake in your signup-login.js file. Correct the code with this -
/* GET Signup Login Page. */
signupLoginRouter.get("/", function(req, res, next) {
res.send('respond with a resource');
});
As per your code the actual url of signup page becomes to "/signup-login/signup-login"
You don't need to add the singup-login url path again in your page. That is already referenced in your main router.

Add an exception to ExpressJS app.use()

I'm working on a NodeJS project, and using Express as my routing framework.
I have a register form in my site, and a login form, both of which send requests to /users (/register and /login respectively). However, I would like to be able to have /users/:userID as routes to see profiles of different users, but of course, this routes imply that I have a session_id for every logged in user.
My question is, how can I use app.use('/users', checkForSessionId), without applying it to register and login?
This is where you need to use middleware
app.js
var users = require('./routes/user');
app.use('/users', users);
./routes/user.js
var express = require('express');
var router = express.Router();
function checkForSessionId(req, res, next){
//if no valid session
// return res.status(401).json("not authorised");
//else
next();
}
router.get('/:userId', checkForSessionId, function(req, res){
//this is a route which requires authentication
})
router.post('/register', function(req, res){
//authentication is not necessary
})
module.exports = router;

One router is not triggered when declaring routers in different files

I would like to breakdown my routes in several files, typically something for the client routes and something for the api.
So I declare my app, then
app.use('/', clientRoutes);
app.use('/api', apiRoutes);
In clientRoutes:
module.exports = function (webapp_client_path){
router.get('/', function (req, res) {
res.sendFile(path.join(webapp_client_path, '/','index.html'));
});
return router;
};
In apiRoutes:
module.exports = function(passport){
router.post('/signup', function(req, res) {
console.log('signup!', req.body);
});
return router;
}
So the problem is that the apiRoutes is not triggered, if I put everything in the same cleintRoutes file it works. I've tried to change the root also ( app.use('/', apiRoutes); and inside the file router.post('/api/signup'...) but it didn't change anything.
I'm pretty sure I'm missing something basic here but can't find what it is yet. Thanks for your help !
I found the problem.
You need to execute the router then pass it as a middleware.
var apiRoutes = require('./routes/apiRoutes')();
app.use('/', apiRoutes);

Categories