skip to Main Content

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 where 5e3063dbfa749d9229bab26f 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


  1. 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 not app.get()

    Hence change app.get('/', postsRoute); to app.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);

    Login or Signup to reply.
  2. The only one reason is because you’re using get twice. First in your index.js and the second one in your dashboard.js. You should not to do that.

    So, to fix it, make sure in your index.js don’t use app.get:

    app.get('/dashboard', dashboardRoute);
    

    Only use app.use:

    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    

    After you use set app.use('/dashboard') in your index.js, make sure in your dashboard.js, like this code below:

    const express = require('express');
    const dashboardController = require('../../controllers/admin/dashboard');
    
    // Express router
    const router = express.Router();
    
    // Dysplay Dashboard
    router.get('/', dashboardController.displayDashboard);
    
    module.exports = router;
    

    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.

    Login or Signup to reply.
  3. 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 route

    Try removing filter from one of them

    Login or Signup to reply.
  4. try to write app.get('/:id', postsRoute); after app.get('/dashboard', dashboardRoute);

    when http://localhost:3000/dashboard url called it will call postRoute route instead of dashboardRoute, because express will recognize ‘/dashboard’ as ‘/:id’, so req.params.id should be equal to ‘dashboard’ inside postRoute

    Login or Signup to reply.
  5. 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

    ...
    const routes = require('./routes/index');
    ... 
    // Middleware
    app.use(morgan('dev'));
    
    app.use('/', routes);
    
    const port = process.env.PORT || 3000;
    

    you need to create routes/index.js file containing something like this:

    const express = require('express');
    const router = express.Router();
    const dashboardController = require('../controllers/admin/dashboard');
    const postsController = require('../controllers/front-end/posts');
    
    // Get Posts
    router.get('/posts', postsController.getPosts);
    
    // Get Single Post
    router.get('/posts/:id', postsController.getSinglePost);
    
    // Display Dashboard
    router.get('/dashboard', dashboardController.displayDashboard);
    
    module.exports = router;
    
    Login or Signup to reply.
  6. Firstly,
    app.use('/:id', postsRoute); and app.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 the app.use('/:id', postsRoute); to app.use('/post/:id', postsRoute); . This will work fine.

    Secondly, according to your code the URL should be http://localhost:3000/dashboard/dashboard, not http://localhost:3000/dashboard.

    index.js

    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('/post/:id', postsRoute); //****changed******
    
    // 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}!`));
    
    Login or Signup to reply.
  7. 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.

    // 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);
    
    

    Here what is happing is
    First now route become like this

    / you added postsRoutes

    So now routes becomes

    / – will gives all posts
    /:id – will gives single post

    Again you added postsRoutes to “:/id”
    /:id – postsRoutes

    so now routes becomes

    /:id will gives all posts
    /:id/:id will give single posts

    So you have to remove any one line from those

    FINE this one only

    // Get Posts
    app.use('/', postsRoute);
    

    And for your dashboard you are done same thing

    app.use('/dashboard', dashboardRoute);

    now routes becomes

    /dashboard/dashboard – it will give dashboard

    but 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 info


    And dashboard routes you need to change

    router.get('/dashboard', dashboardController.displayDashboard);
    
    /dashboard -> "/"
    
    router.get('/', dashboardController.displayDashboard);
    

    Final routes will be

    const postsRoute = require('./routes/front-end/posts');
    
    // Get Posts
    app.use('/posts', postsRoute);
    
    // Get Single Post
    // THIS ONE WILL COMMENT 
    // app.use('/posts/:id', postsRoute);
    
    // Bring the Dashboard
    const dashboardRoute = require('./routes/admin/dashboard');
    
    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    

    In dashboard routes

    router.get('/', dashboardController.displayDashboard);
    
    Login or Signup to reply.
  8. You are not configuring your routes correctly in your index.js file.
    Try this:

    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');
    
    const dashboardRoute = require("./routes/admin/dashboard");
    
    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    
    // Get Posts
    app.use('/', postsRoute);
    
    const port = process.env.PORT || 8080;
    
    app.listen(port, () => console.log(`Example app listening on port ${port}!`));
    

    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).

    Login or Signup to reply.
  9. Your routing issue could be fixed with replacing the order of /:id and /dashboard.

    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);
    
    ///////////////////////UPDATED PART/////////////////////////////////////
    // Bring the Dashboard
    const dashboardRoute = require('./routes/admin/dashboard');
    
    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    
    // Get Single Post
    app.use('/:id', postsRoute);
    ////////////////////////////////////////////////////////////////////////
    
    
    const port = process.env.PORT || 3000;
    
    app.listen(port, () => console.log(`Listening on port ${port}!`));
    
    Login or Signup to reply.
  10. FIXED IT, for complete running example clone node-cheat XPressBlog and run node index followed by npm i.

    Point browser to http://localhost:3000/dashboard, outputs:

    This is Dashboard

    http://localhost:3000, outputs:

    This will load all posts; continue with your logic!

    http://localhost:3000/my-great-post, outputs:

    This will load single post with slug : my-great-post

    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:

    const dashboardRoute = require("./routes/admin/dashboard");
    app.use('/dashboard', dashboardRoute);
    
    const postsRoute = require('./routes/front-end/posts');
    app.use('/', postsRoute);
    

    In case you wish to explore more about app.use here are the links:

    Login or Signup to reply.
  11. You only need to add postRoute once in index.js,

    // Bring the Dashboard
    const dashboardRoute = require("./routes/admin/dashboard");
    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    // Bring the Posts Routes
    const postsRoute = require('./routes/front-end/posts');
    // Get Posts
    app.use('/', postsRoute);
    

    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

    router.get('/', dashboardController.displayDashboard);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search