NodeJs setting up production and development - node.js

I was learning NodeJs advance concepts after going through the basic course.
I am following stepehen grinder course where we would be using his folliwng repo
I was initially walking through the repo where somethings were sort of new to me
My main question evolves around his index.js file in repo
This isn't prime question but first he have done something like this
require('./routes/authRoutes')(app);
require('./routes/blogRoutes')(app);
Is this equivalent to something like this
const auth = require('./routes/auth.js')
const profile = require("./routes/profile.js")
app.use('/auth', auth)
app.use('/profile', profile)
Second, Primary question, In his index.js file he have done something like this
if (['production'].includes(process.env.NODE_ENV)) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve('client', 'build', 'index.html'));
});
}
This does not make sense to me at all, can someone explain me what does the above code do? and an interesting article which can help me comprehend.
Also, Can someone please tell me what does path module do? I went through their do documentation and was able to comprehend that path allows us to access files outside our node project. Is that correct understanding?

Concerning you first question:
It's not the same. app.use(...) defines a middleware that gets executed on all and every routes. Here, both routes files export a function which takes one argument: the application (ExpressJS server) instance.
So, require('./routes/blogRoutes') gives you a function app => {...}, and by adding parenthesis and the app variable as a parameter you immediately execute this function with the current server (application) instance. Which in the end will create all the routes defined in the route file.
Concerning your second question:
The if is testing if the NODE_ENV variable is equal to production. If it is in production mode, app.use(express.static('client/build')); tells ExpressJS to serve static files from the client/build folder.
The rest of the code app.get('*', ...) send the index.html file for calls made to any route except the one defined in the two routes files.
The path.resolve only role is to easily build the absolute path of the index.html file.

Related

Heroku Node/React Deployment Routes Everything to index.html

I have an app.js node main file where I define my api path as the following
app.get('/api/users', UserController.get);
Below in the same file I have the following
app.use(express.static(path.resolve(__dirname, "./front/build")));
app.get("*", function (request, response) {
response.sendFile(path.resolve(__dirname, "./front/build", "index.html"));
});
The index.html successfully serves React App.
If I open my heroku app somewhere at my-app.herokuapp.com it will open the React app which is intended but the Problem is my-app.herokuapp.com/api/users also serves index.html file instead of JSON that the endpoint is supposed to return.
I tried
I replaced endpoint route definition to come before the "" definition (didn't suffice)
EVEN more, I removed redirection to index.html but heroku still opens the index.html page with any type of request (the "" redirection still works). So, it might have cached something?
Is it about cache (how to clean?) or any other suggestions?
You should create routes and work in a proper flow for each functionality,
For Example:
//app.js
app.use("/api/user",userRoutes);
//UserRoutes
router.post("/signup",UserController.signup);
//UserController
exports.signup = async (req,res,next) => {
//Signup function to add a new user when the user provides required info
}
In this way, you code will be easily accessible and much efficient

Register new route at runtime in NodeJs/ExpressJs

I want to extend this open topic: Add Routes at Runtime (ExpressJs) which sadly didn't help me enough.
I'm working on an application that allows the creation of different API's that runs on NodeJs. The UI looks like this:
As you can see, this piece of code contains two endpoints (GET, POST) and as soon as I press "Save", it creates a .js file located in a path where the Nodejs application is looking for its endpoints (e.g: myProject\dynamicRoutes\rule_test.js).
The problem that I have is that being that the Nodejs server is running while I'm developing the code, I'm not able to invoke these new endpoints unless I restart the server once again (and ExpressJs detects the file).
Is there a way to register new routes while the
NodeJs (ExpressJs) is running?
I tried to do the following things with no luck:
app.js
This works if the server is restarted. I tried to include this library (express-dynamic-router, but not working at runtime.)
//this is dynamic routing function
function handleDynamicRoutes(req,res,next) {
var path = req.path; //http://localhost:8080/api/rule_test
//LoadModules(path)
var controllerPath = path.replace("/api/", "./dynamicRoutes/");
var dynamicController = require(controllerPath);
dynamicRouter.index(dynamicController[req.method]).register(app);
dynamicController[req.method] = function(req, res) {
//invocation
}
next();
}
app.all('*', handleDynamicRoutes);
Finally, I readed this article (#NodeJS / #ExpressJS: Adding routes dynamically at runtime), but I couldn't figure out how this can help me.
I believe that this could be possible somehow, but I feel a bit lost. Anyone knows how can I achieve this? I'm getting a CANNOT GET error, after each file creation.
Disclaimer: please know that it is considered as bad design in terms of stability and security to allow the user or even administrator to inject executable code via web forms. Treat this thread as academic discussion and don't use this code in production!
Look at this simple example which adds new route in runtime:
app.get('/subpage', (req, res) => res.send('Hello subpage'))
So basically new route is being registered when app.get is called, no need to walk through routes directory.
All you need to do is simply load your newly created module and pass your app to module.exports function to register new routes. I guess this one-liner should work just fine (not tested):
require('path/to/new/module')(app)
Is req.params enough for you?
app.get('/basebath/:path, (req,res) => {
const content = require('content/' + req.params.path);
res.send(content);
});
So the user can enter whatever after /basepath, for example
http://www.mywebsite.com/basepath/bergur
The router would then try to get the file content/bergur.js
and send it's contents.

How to prevent express server from serving api routes from the static folder

Hi I need some help with how express handles routes.
In setting up my express app, I have something like this:
app.use(express.static('public'));
Next, I mount some api routes:
app.use('/api', myrouter);
app.get('*', function(req, res) {
res.sendFile(path.resolve('public/index.html'));
});
But, when the frontend requests data via an api route, e.g. at 'localhost:3000/api/things', I am seeing in the Express debug logs that at some point (unsure when) it actually tries to serve this request as a static file, like:
send stat "C:\myproject\public\api\things" +230ms
Even though this folder doesn't exist in 'public' and should be solely handled by my api. FYI, the handler for /api/things route is only implemented for the GET method, and does get invoked at some point.
How do I stop express server from also trying to serve api requests from the static folder?
Thanks very much.
Answering my own question... which appears to be a duplicate of this one:
`express.static()` keeps routing my files from the route
So the answer is this one: https://stackoverflow.com/a/28143812/8670745
In short, the app.use() declarations that mount your api routers should appear before the app.use() statements which tell express.static where to serve your static files from. This way, the latter acts as a catchall AFTER api route handling is done. Router engine order matters...
Your answer is misinformed, or rather you've misinterpreted the problem. Your original configuration:
app.use(express.static(__dirname + 'public'));
app.use('/api', myrouter);
Looks absolutely fine because there's no clash between the routes. The threads you've linked too aren't really the same, and I can see why moving the routes in those cases would have worked.
The only thing I'd say is your path to your static folder isn't reliable, you should really use path.join, or actually in your case you can just do express.static('public') - express will infer the folder your app is served from.

How to serve user specific static content in Express.js

I want to serve user-specific static content in Express. That means, if a user is logged in, his private static folder is served by express. Other users shall not have access.
I tried the following (see below), but the static content is not being served. In fact, the route seems to be completely ignored and I get a 404.
I am not sure if the way I do it is the right way to go and if express is capable of dynamically serving different static folders. Thanks in advance for your thoughts on this.
Here's the code (simplified):
routes.js:
express = require 'express'
router = express.Router()
router.use '/user/assets', (req, res, next) ->
if req.user
userpath = 'uploads/' + md5(req.user._id)
if not fs.existsSync userpath
fs.mkdirSync userpath
console.log "Created user directory at " + userpath
express.static(userpath)
next()
module.exports = router
index.js:
express = require 'express'
app = express()
app.use '/', require './routes'
Sidenotes:
The md5 is just a way of escaping weird characters in the user id, which is a string. I know there is a possibility for a mismatch, which is tiny, and about which I don't wanna care for now. Concerns about general security of the fashion of the solving attempt are appreciated.
The code is written in CoffeeScript.
req.user contains a valid user element.
Just calling express.static is not enough, you need to use() it with the router. Unfortunately you can't directly do that, since you require a different set of routes for each user.
Calling express.static will return a middleware function. You could call it directly, i.e. something like this:
var files = express.static(userpath);
return files(req, res, next);
However that's still not enough, as the middleware uses req.url to build the file path. The express router adjusts this property and removes the mount point (see req.originalUrl in the docs). So you need to strip /user/assets from it, before calling the middleware.
By the way, you should set the DEBUG environment variable for node. It allows you to see what routes are created by express, which is very handy in debugging express.static 404 problems. E.g. you'd do $ DEBUG=* node index.js on Linux.
As you can see the approach starts to be a bit hacky and creating a new express.static middleware on each request is not very performance friendly too. So depending on what your user directories contain, using res.sendFile might actually be better.
As a sidenote, I assume you've checked that req.user actually contains something if the user is logged in.

Use non-absolute Paths with node.js and express

i'm having issues running my node server on localhost.
right now it only allows me to run it with a static path:
app.get("/", function(req, res){
res.sendFile("/Users/name/Documents/_privat/dungeon/index.html");
});
of course that's not where i wanna go.
i tried many ways to embedd the dynamic path, this is my file-structure:
*dungeonapp
- main.html
- js
--client
---main.js (and others)
--server
---server.js
- style
--style.css
So if I run everything static my application runs on localhost, but it also won't load my css files neither the js files.
Where am i going wrong? all the regular path embedding didn't work like "/../index.html"
Express response sendFile() method has a second options argument where you can express your root path for path resolution. See docs for more information. You can use {root: __dirname} as second argument to sendFile() and file paths will be resolved relative to the javascript file that calls sendFile(). In your case with the directory structure indicated in your question the code on server.js would be:
app.get("/", function(req, res){
res.sendFile("../../main.html", {root: __dirname});
});
This way you can move your project to any folder and sendFile() will continue to work. I think you should reword your question because you are talking about absolute paths and not static paths.
Normally you would do something like have two subfolders in the root of your project, one for server code and one for client (i.e. web) code and then you can use app.use(express.static('<filepath>')) in your server code to serve the static client files.
As an example, in my project root I have 2 folders, one called app and one called web. In the main app.js, I have app.use(express.static(__dirname + '/../web/')); which serves the static content. Normally this would be the first use of app.use() so that none of the other routes need to be checked before your content is served.

Resources