How to route in Node.js/React.js Web App? - javascript

I'm creating a Next.js Frontend - Express.js Backend Web App.
I have some problems with routing. In the official documentation of Next.js, I read that if we use a custom server, we have to disable the automatic routing that uses the folder /pages to work.
module.exports = {
useFileSystemPublicRoutes: false,
}
But at this point, how can I route the pages. I'm thinking to still use the /pages folder to group the several pages.
How can i route from backend? Have I to import in some way the javascript
pages? Like this code...
router.get('/users', function (req, res) { "import Next.js page" });
Or it's antoher type of process like use "react-router".
Can anyone give me an example of the best choice? Thanks

You can use next-routes.
// server.js
const next = require('next')
const routes = require('./routes')
const app = next({dev: process.env.NODE_ENV !== 'production'})
const handler = routes.getRequestHandler(app)
// With express
const express = require('express')
app.prepare().then(() => {
express().use(handler).listen(3000)
})
// Without express
const {createServer} = require('http')
app.prepare().then(() => {
createServer(handler).listen(3000)
})
and your routes.js file
const routes = module.exports = require('next-routes')()
routes
.add('about')
.add('blog', '/blog/:slug')
.add('user', '/user/:id', 'profile')

Related

Express routing - prevent app.use('/') top-level path middleware from executing when visiting child/nested paths directly

So I'm not really sure if the title is descriptive enough, but here is a super simple example.
My site has a public area and a restricted admin area.
example.com/admin (admin home page)
example.com/admin/news (news page)
example.com/admin/posts (posts page)
And because I don't want people who aren't administrators or logged in to be able to access it, I have a simple middleware function to check for cookies.
app.js
const express = require('express');
const app = express();
const authMiddleWere = async (req, res, next) => {
// pseudo-code, do some cookie validity check here
console.log(`Route: ${req.url}`)
if (cookie) {
next();
}
};
const adminRouter = require('./routes/private/home');
const newsRouter = require('./routes/private/news');
const postsRouter = require('./routes/private/posts');
app.use('/admin/', authMiddleWere, adminRouter);
app.use('/admin/news', authMiddleWere, newsRouter);
app.use('/admin/posts', authMiddleWere, postsRouter);
/routes/private/home.js
const express = require('express');
const router = express.Router();
router.get('/', async (req, res, err) => {
res.render('private/home');
});
module.exports = router;
The problem here is that this authMiddleWere function gets called twice when I visit nested paths such as example.com/admin/news which shares the same pattern - it's starting with /admin/......
I can tell that for sure because we are logging the req.url in our middleware function so if I go to example.com/admin it will log out:
Route: /
But if I go to example.com/admin/news it will log out both:
Route: /
Route: /news
So what is causing this and how do I work my way around it? I'm assuming that what I described is the intended behavior of Express.js so I am looking for a way to get around this or (re)structure my code better.
Cheers!
You can use a regex for your route.
app.use(/\/admin$/, authMiddlewear, authRouter);
This will match only routes that end in admin. You may need to handle cases where the route is /admin/ instead of /admin, but iirc, express handles that intelligently.
Well one way you can fix this is by creating a separate route file and splitting everything into a MVC manner. For example:
Inside your main app.js just create a route pointing to the /admin like so:
app.use('/admin', authMiddleWere, require('./src/your-route-to-the-file/admin.route'));
Inside the admin.route file, call your controller like this:
const express = require("express");
const router = express.Router();
const mainAdminCtrl = require("../controllers/admin.controller");
router.get("/news", mainAdminCtrl.adminAuthDisplay);
module.exports = router;
Where the const mainAdminCtrl is your controller and the function adminAuthDisplay is your service.
Essentially, you are splitting your functionality in to a dedicated router, controller and service file. So when you try to access the route /admin, it will look for any suffix inside the router file.
In a case where you want to access the /news endpoint, your API will only make the call once.
If this helps, I can expand my explanation further.

I want to use res.sendfile but the path is not correct error comes up

I have a server Express.js and 3 html, JS frontend pages I want to access my homepage in localhost:3000 and then go to /register to render my register.html page but I can't do the path here is a screenshot of my folder
enter image description here
and Here is my code
res.sendFile(__dirname + "./FRONT/REGISTER/register.html")
This Gives me an error :
{"error":{"message":"ENOENT: no such file or directory, stat '/Users/hazem/Desktop/Web-Development/full-stack-blogs/api/routes../FRONT/REGISTER/register.html'"}}
Also It gives me an error that app is not defined in my registerUsers.js :
Here are my Routes --> registerUsers.js
const express = require("express");
const router = express.Router();
app.use(express.json());
// Handle incoming post requests to /register
router.post('/register',(req,res,next)=>{
const user= {
userName:req.userName,
email:req.email,
password:req.password,
sex:req.sex
};
res.status(201).json({
message:"Handling post requests to /register",
user:user
})
})
module.exports = router;
app is undefined because you didn't import this like const app = require('path of your app file); also make sure you do module.exports = app; in your app.js file or another way to export it.
From what file do you use this res.sendFile(__dirname + "./FRONT/REGISTER/register.html") ? Please also use the path module from nodeJs to create your paths (https://nodejs.org/api/path.html).
If you use this statement from registerUsers.js your path should be : path.join(__dirname, "../FRONT/REGISTER/register.html); note the ../
You would import path like : const path = require('path'); and use it with your res.sendFile like this:
res.sendFile(path.join(__dirname, "FRONT/REGISTER/register.html"));
I hope this helped, good luck!

Middleware in MVC structure with expressJS

I am creating an MVC structured app. For me this is a new concept. I am having trouble as where to place my middleware. Here's how my app is structured:
Server:
//routes
app.use('/' , userRoutes);
User routes :
//controllers
const postUser = userController.postUser;
const getUser = userController.getUser;
//route
router.route('/user').post(postUser).get(getUser);
And my controllers :
const {check, validationResult } = require('express-validator');
const postUser = (req,res) => {
res.send(req.body);
console.log('POSTED')
};
const getUser = (req,res) => {
res.send(req.body );
console.log('GOTTEM');
};
module.exports = {postUser , getUser};
Where in this bunch should i implement my middleware. I want to use express-validator to check for fields etc, so it has to sit in between the requested path and the callback. Im a bit confused as to where to add my middleware.
It's My Suggestion to use express Boiler Plate for Better MVC Directory Structure and better Routes Understanding.
So after trying some things out myself i've figured it out.
In my routers where i chain all the methods to a specific route:
router.route('/user').post(middleware,postUser).get(getUser);
This worked for me.

Express routes work when serving locally but fail once deployed

I am building a blog using Node js and Express and hosting it on firebase. When I serve the website locally everything works just fine and the html is served as expected. But, when I deploy the server the routes no longer work and the html files can't be found. I'm sure it has to do with how firebase deploy hold the html files.
I'm not really sure where to go from here. I can't really find great guidance on how to set up something like this on the firebase docs.
const functions = require("firebase-functions")
const cors = require("cors")
const express = require("express")
const path = require("path")
/* Express with CORS */
const app = express()
app.use(cors({ origin: true }))
app.get("/", (request, response) => {
response.send("Hello from Express on Firebase with CORS!")
})
//File path consts
const publicDir = "/Users/wilson/wildman-talks-fb/public";
const blogDir = "/Users/wilson/wildman-talks-fb/public/blogs";
app.get("/about/", (req, res) =>{
res.sendFile(path.join(publicDir, "/about.html"));
});
app.get("/contact/", (req, res) =>{
res.sendFile(path.join(publicDir, "/contact.html"));
});
app.get("/tools/", (req, res) =>{
res.sendFile(path.join(publicDir, "/tools.html"));
});
app.get("/five-steps-july-20/", (req, res) =>{
//res.send(path.join(publicDir, "/five-steps-july-20.html"));
res.sendFile(path.join(publicDir, "/five-steps-july-20.html"));
})
exports.app = functions.https.onRequest(app)
So what is happening is when I deploy the site locally all of the links in my webpage work to other html webpages for my site. When I deploy it on firebase I get 404 errors. I was able to use path.join(__dirname, "../public") and print out all of the files contained there. When i did that these were the files that were there on my local host: [".DS_Store","404.html","about.html","blogs","contact.html","css","five-steps-july-20.html","img","index.html","js","mail","tools.html","vendor"]. After deploying it just returns me a 500 error so I guess that won't help.
Your directories contain absolute paths to your filesystem. Try to use dynamic absolute paths.
Change the paths from
const publicDir = "/Users/wilson/wildman-talks-fb/public";
const blogDir = "/Users/wilson/wildman-talks-fb/public/blogs";
To
const path = require("path");
const publicDir = path.join(__dirname, "/public";)
const blogDir = path.join( __dirname, "/public/blogs");

Setup create-react-app with Express

Problem - I am not able to get any response from postman when hitting localhost:9000. It should give me a user json back which is in my routes file only for time being. Instead it spits out the following.
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="/static/js/main.ce2f0561.js"></script>
</body>
Setup
Using create-react-app with express to connect.
My folder structure is
--src React app lives in this
--server
-- index.js
-- express.js
-- controllers
-- routes
-- rs_notes.js
rs_routes.js
'use strict';
module.exports = function(router){
const notesController = require('../controllers/cs_notes');
router.route('/', function(req, res, next) {
// Comment out this line:
//res.send('respond with a resource');
// And insert something like this instead:
res.json([{
id: 1,
username: "samsepi0l"
}, {
id: 2,
username: "D0loresH4ze"
}]);
});
};
express.js
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const app = express();
const router = express.Router();
// Setup logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));
require('./routes/rs_notes')(router);
// Always return the main index.html, so react-router render the route in the client
router.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
module.exports = app;
index.js
'use strict';
const app = require('./express');
const PORT = process.env.PORT || 9000;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
Full project link - https://drive.google.com/file/d/0B35OQMkRo3KcSHlkeXdWVjVjc0U/view?usp=sharing
My questions or doubts are
Am I passing the router in a right way. We used to pass app in this
way prior to express 4 ? So not sure if same structure works here.
I am able to load it in browser by hitting localhost:9000 (server is run by node server command as configured) but not in postman.
I was able to fix up this stack by learning the use of Router appropriately and moving some code here and there. But it was still not working for base route i.e when I simply do router.get('/', ...). Gives the same error message. So I rather reversed the approach of connecting node and react. I published my efforts on medium for the same reason as two separate posts.
https://medium.com/#kushalvmahajan/i-am-about-to-tell-you-a-story-on-how-to-a-node-express-app-connected-to-react-c2fb973accf2

Categories

Resources