I am working on a blogging application (click the link to see the GitHub repo) with Express, EJS and MongoDB.
For a reason I have been unable to identify, when (in the browser) I try to go to: http://localhost:3000/dashboard
it (the browser) get stuck in a loading state and never actually loads the dashboard route.
In the “entry” index.js file I have:
const express = require('express');
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const path = require('path');
const morgan = require('morgan');
const expressLayouts = require('express-ejs-layouts');
const app = express();
dotenv.config();
//Conect to MONGODB
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log('conected');
});
mongoose.connection.on('error', err => {
console.log(`DB connection error: ${err.message}`);
});
// Set static directory
app.use(express.static(path.join(__dirname, 'public')));
// Set views directory
app.set('views', path.join(__dirname, 'views'));
// Set view engine
app.set('view engine', 'ejs');
// Use Express Layouts
app.use(expressLayouts);
// Middleware
app.use(morgan('dev'));
// Bring the Posts Routes
const postsRoute = require('./routes/front-end/posts');
// Get Posts
app.use('/', postsRoute);
// Get Single Post
app.use('/:id', postsRoute);
// Bring the Dashboard
const dashboardRoute = require('./routes/admin/dashboard');
// Get Dashboard
app.use('/dashboard', dashboardRoute);
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}!`));
In the dashboard route (routesadmindashboard.js) I have:
const express = require('express');
const dashboardController = require('../../controllers/admin/dashboard');
// Express router
const router = express.Router();
// Dysplay Dashboard
router.get('/dashboard', dashboardController.displayDashboard);
module.exports = router;
While in the dashboard controller:
const Post = require('../../models/post');
exports.displayDashboard = (req, res, next) => {
res.send('Dashboard');
};
in routes/front-end/posts.js
I have:
const express = require('express');
const postsController = require('../../controllers/front-end/posts');
// Express router
const router = express.Router();
// Get Posts
router.get('/', postsController.getPosts);
// Get Single Post
router.get('/:id', postsController.getSinglePost);
module.exports = router;
The posts controller:
const Post = require('../../models/post');
exports.getPosts = (req, res, next) => {
const posts = Post.find({}, (err, posts) => {
if(err){
console.log('Error: ', err);
} else {
res.render('default/index', {
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
posts: posts
});
}
});
};
exports.getSinglePost = (req, res, next) => {
let id = req.params.id;
if (id.match(/^[0-9a-fA-F]{24}$/)) {
Post.findById(id, function(err, post){
if(err){
console.log('Error: ', err);
} else {
res.render('default/singlepost', {
layout: 'default/layout',
website_name: 'MEAN Blog',
post: post
});
}
});
}
};
IMPORTANT:
It is necessary that every single post is displayed under the root url, for example:http://localhost:3000/5e3063dbfa749d9229bab26f
where5e3063dbfa749d9229bab26f
is, of course the post id.
This is for SEO purposes. I intent to later replace id with post slug: http://localhost:3000/my-great-post
.
How can I achieve this?
11
Answers
in your entry file
index.js
, you are registering the routes in the wrong way.To register routes, you have to use
app.use()
and notapp.get()
Hence change
app.get('/', postsRoute);
toapp.use('/', postsRoute);
Let me know if this worked.
Edit: after looking again I saw you are adding the prefix “dashboard” twice to the route.
So change the line:
app.get('/dashboard', dashboardRoute);
to
app.use('/', dashboardRoute);
So, to fix it, make sure in your
index.js
don’t useapp.get
:Only use
app.use
:After you use set
app.use('/dashboard')
in yourindex.js
, make sure in yourdashboard.js
, like this code below:Now, you can call your endpoint with url:
localhost:3000/dashboard
.For an example of your code, you can look at my codesanbox: https://codesandbox.io/s/express-ejs-bug-answer-0nyo9
I hope it can help you.
You’re applying 2 filters.
First in
app.get('/dashboard', dashboardRoute);
and then in
router.get('/dashboard', dashboardController.displayDashboard);
.So you’re probably creating
http://localhost:3000/dashboard/dashboard
routeTry removing filter from one of them
try to write
app.get('/:id', postsRoute);
afterapp.get('/dashboard', dashboardRoute);
when
http://localhost:3000/dashboard
url called it will callpostRoute
route instead ofdashboardRoute
, because express will recognize ‘/dashboard’ as ‘/:id’, soreq.params.id
should be equal to ‘dashboard’ insidepostRoute
You need to reorganize your routes. Your app architecture looks confusing. If you are using express Router then you need to do something like this:
your index.js
you need to create routes/index.js file containing something like this:
Firstly,
app.use('/:id', postsRoute);
andapp.use('/dashboard', dashboardRoute);
are same to the browser. Cause when the browser gets ‘/dashboard’, it doesn’t know whether the string ‘dashboard’ is a id or not. Because of that, it gets stuck as the URL indicates to both of these routes. So change theapp.use('/:id', postsRoute);
toapp.use('/post/:id', postsRoute);
. This will work fine.Secondly, according to your code the URL should be
http://localhost:3000/dashboard/dashboard
, nothttp://localhost:3000/dashboard
.index.js
In Index.js you are adding routes exports to “/” , in express routes paths will match with regular expression. so when added router to “/” so everything will be start from here.
Here what is happing is
First now route become like this
/
you added postsRoutesSo now routes becomes
/
– will gives all posts/:id
– will gives single postAgain you added postsRoutes to “:/id”
/:id
– postsRoutesso now routes becomes
/:id
will gives all posts/:id/:id
will give single postsSo you have to remove any one line from those
FINE this one only
And for your dashboard you are done same thing
app.use('/dashboard', dashboardRoute)
;now routes becomes
/dashboard/dashboard
– it will give dashboardbut this one override the “/:id/:id” routing matching so everthing now override by this one
so create another route for getting the posts like
app.use("/posts", postsRoute);
/posts
-> it will give all posts/posts/:id
-> it will give single infoAnd dashboard routes you need to change
Final routes will be
In dashboard routes
You are not configuring your routes correctly in your index.js file.
Try this:
You don’t need to use two postsRoutes. Check this: https://expressjs.com/en/guide/routing.html
Also I suggest you add your post route like so:
app.use('/post, postsRoute).
Your routing issue could be fixed with replacing the order of
/:id
and/dashboard
.FIXED IT, for complete running example clone node-cheat XPressBlog and run
node index
followed bynpm i
.Point browser to http://localhost:3000/dashboard, outputs:
http://localhost:3000, outputs:
http://localhost:3000/my-great-post, outputs:
What you were doing wrong?
You were confusing the use of
app.use(
, so those are fixed as per your needs (as mentioned in your post) like this:In case you wish to explore more about
app.use
here are the links:You only need to add postRoute once in index.js,
and in the dashboardRoute file change the route to ‘/’ instead of ‘/dashboard’, else you need to use localhost:3000/dashboard/dashboard to get the dashboard