NodeJS Express defining custom routes - javascript

This is probably a really basic concept that I'm not understanding but in my NodeJS application I am trying to define a custom route.
my directory structure is as follows
/application
/app.js
/package.json
/node_modules
/public
/routes
/control
/users.js
/views
/control
/users.ejs
Which I am happy with because I want to keep the routes and views in a 1 to 1 relationship because I will eventually end up with something like
/application
/app.js
/package.json
/node_modules
/public
/routes
/control
/users.js
/system.js
/tools
/stock.js
/report.js
/views
/control
/users.ejs
/system.ejs
/tools
/stock.ejs
/report.ejs
So I don't want to end up with a /routes/index.js file with a hideous amount of routing code inside.
It seems to work while my app.js file is as follows
//==============================================================================
// setup
//==============================================================================
var express = require("express");
var path = require("path");
var app = express();
var port = 3000;
var message = null;
app.set("view engine", "ejs");
app.use(express.static(path.join(__dirname, "public")));
//==============================================================================
// routes
//==============================================================================
var users = require("./routes/control/users");
app.get("/", users.users);
//==============================================================================
// start server
//==============================================================================
app.listen(port, function() {
message = "Server Started : Port " + port;
console.log(message);
});
Although I can see this is going to end up looking like
//==============================================================================
// setup
//==============================================================================
var express = require("express");
var path = require("path");
var app = express();
var port = 3000;
var message = null;
app.set("view engine", "ejs");
app.use(express.static(path.join(__dirname, "public")));
//==============================================================================
// routes
//==============================================================================
// control
var users = require("./routes/control/users");
app.get("/", users.users);
var system = require("./routes/control/system");
app.get("/", system.system);
// tools
var stock = require("./routes/tools/stock");
app.get("/", stock.stock);
var report = require("./routes/tools/report");
app.get("/", report.report);
//==============================================================================
// start server
//==============================================================================
app.listen(port, function() {
message = "Server Started : Port " + port;
console.log(message);
});
So I don't really want to have that many requires but doing it like the following doesn't seem to work and I'm not sure why
// control
var control = require("./routes/control");
app.get("/", control.users.users);
app.get("/", control.system.system);
// tools
var tools = require("./routes/tools");
app.get("/", tools.stock.stock);
app.get("/", tools.report.report);

You can use the express Router object to chain your routes. Here's an example
/app.js
var routes = require('./routes/index');
// as noted by Paul in the comments,
// you could use `app.use(routes)` for simplicity
app.use('/', routes);
/routes/index.js
var routes = require('express').Router();
routes.route('/test')
.get(function (req, res) {
res.send(req.originalUrl);
});
routes.use('/control', require('./control/user'));
module.exports = routes;
/routes/control/user.js
var routes = require('express').Router();
routes.route('/test')
.get(function (req, res) {
res.send(req.originalUrl);
});
module.exports = routes;
So for the route defined in index.js, you'll need to send a GET request to /test while in user.js, you will need to send a GET request to /control/test to get a response.
This way all you need to include in the main js file, app.js in your case, is the main routes file, which is index.js under the routes directory. Either way, you will still need to do one require statement for each file that exports a router object.

When you say:
var control = require("./routes/control");
Node will do the followings:
Since you privided a relative path to require, it will search for a routes directory within the current folder and in that directory search for a control.js file. It can't find control.js file so then:
Search for a control.json file. but it also can't find that
file. then:
Search for a control directory. It finds such a directory. opens
it and search for a package.json file to look into its
main property. but it also cant find such a file. then:
Search for a index.js file but also there is no such a file
By default when you give a folder path to require, it does not load .js files inside that folder automatically it looks for package.json file and if it's not there it loads index.js. i. e. It looks for an entry point.
So make an index.js in your control folder:
/routes
/control
/users.js
/system.js
/index.js
index.js:
module.exports = {
users: require('./users');
system: require('./system');
};
Do this also for your tools directory and your last approach should work.
Note that you could consider using express.Router to manage routes.

Related

How to create HTML pages with images with NodeJS [duplicate]

I want to serve index.html and /media subdirectory as static files. The index file should be served both at /index.html and / URLs.
I have
web_server.use("/media", express.static(__dirname + '/media'));
web_server.use("/", express.static(__dirname));
but the second line apparently serves the entire __dirname, including all files in it (not just index.html and media), which I don't want.
I also tried
web_server.use("/", express.static(__dirname + '/index.html'));
but accessing the base URL / then leads to a request to web_server/index.html/index.html (double index.html component), which of course fails.
Any ideas?
By the way, I could find absolutely no documentation in Express on this topic (static() + its params)... frustrating. A doc link is also welcome.
If you have this setup
/app
/public/index.html
/media
Then this should get what you wanted
var express = require('express');
//var server = express.createServer();
// express.createServer() is deprecated.
var server = express(); // better instead
server.configure(function(){
server.use('/media', express.static(__dirname + '/media'));
server.use(express.static(__dirname + '/public'));
});
server.listen(3000);
The trick is leaving this line as last fallback
server.use(express.static(__dirname + '/public'));
As for documentation, since Express uses connect middleware, I found it easier to just look at the connect source code directly.
For example this line shows that index.html is supported
https://github.com/senchalabs/connect/blob/2.3.3/lib/middleware/static.js#L140
In the newest version of express the "createServer" is deprecated. This example works for me:
var express = require('express');
var app = express();
var path = require('path');
//app.use(express.static(__dirname)); // Current directory is root
app.use(express.static(path.join(__dirname, 'public'))); // "public" off of current is root
app.listen(80);
console.log('Listening on port 80');
express.static() expects the first parameter to be a path of a directory, not a filename. I would suggest creating another subdirectory to contain your index.html and use that.
Serving static files in Express documentation, or more detailed serve-static documentation, including the default behavior of serving index.html:
By default this module will send “index.html” files in response to a request on a directory. To disable this set false or to supply a new index pass a string or an array in preferred order.
res.sendFile & express.static both will work for this
var express = require('express');
var app = express();
var path = require('path');
var public = path.join(__dirname, 'public');
// viewed at http://localhost:8080
app.get('/', function(req, res) {
res.sendFile(path.join(public, 'index.html'));
});
app.use('/', express.static(public));
app.listen(8080);
Where public is the folder in which the client side code is
As suggested by #ATOzTOA and clarified by #Vozzie, path.join takes the paths to join as arguments, the + passes a single argument to path.
const path = require('path');
const express = require('express');
const app = new express();
app.use(express.static('/media'));
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'media/page/', 'index.html'));
});
app.listen(4000, () => {
console.log('App listening on port 4000')
})
If you have a complicated folder structure, such as
- application
- assets
- images
- profile.jpg
- web
- server
- index.js
If you want to serve assets/images from index.js
app.use('/images', express.static(path.join(__dirname, '..', 'assets', 'images')))
To view from your browser
http://localhost:4000/images/profile.jpg
If you need more clarification comment, I'll elaborate.
use below inside your app.js
app.use(express.static('folderName'));
(folderName is folder which has files) - remember these assets are accessed direct through server path (i.e. http://localhost:3000/abc.png (where as abc.png is inside folderName folder)
npm install serve-index
var express = require('express')
var serveIndex = require('serve-index')
var path = require('path')
var serveStatic = require('serve-static')
var app = express()
var port = process.env.PORT || 3000;
/**for files */
app.use(serveStatic(path.join(__dirname, 'public')));
/**for directory */
app.use('/', express.static('public'), serveIndex('public', {'icons': true}))
// Listen
app.listen(port, function () {
console.log('listening on port:',+ port );
})
I would add something that is on the express docs, and it's sometimes misread in tutorials or others.
app.use(mountpoint, middleware)
mountpoint is a virtual path, it is not in the filesystem (even if it actually exists). The mountpoint for the middleware is the app.js folder.
Now
app.use('/static', express.static('public')`
will send files with path /static/hell/meow/a.js to /public/hell/meow/a.js
This is the error in my case when I provide links to HTML files.
before:
<link rel="stylesheet" href="/public/style.css">
After:
<link rel="stylesheet" href="/style.css">
I just removed the static directory path from the link and the error is gone. This solves my error one thing more don't forget to put this line where you are creating the server.
var path = require('path');
app.use(serveStatic(path.join(__dirname, 'public')));
You can achieve this by just passing the second parameter express.static() method to specify index files in the folder
const express = require('express');
const app = new express();
app.use(express.static('/media'), { index: 'whatever.html' })

Why GET method make a request for css file [duplicate]

I want to serve index.html and /media subdirectory as static files. The index file should be served both at /index.html and / URLs.
I have
web_server.use("/media", express.static(__dirname + '/media'));
web_server.use("/", express.static(__dirname));
but the second line apparently serves the entire __dirname, including all files in it (not just index.html and media), which I don't want.
I also tried
web_server.use("/", express.static(__dirname + '/index.html'));
but accessing the base URL / then leads to a request to web_server/index.html/index.html (double index.html component), which of course fails.
Any ideas?
By the way, I could find absolutely no documentation in Express on this topic (static() + its params)... frustrating. A doc link is also welcome.
If you have this setup
/app
/public/index.html
/media
Then this should get what you wanted
var express = require('express');
//var server = express.createServer();
// express.createServer() is deprecated.
var server = express(); // better instead
server.configure(function(){
server.use('/media', express.static(__dirname + '/media'));
server.use(express.static(__dirname + '/public'));
});
server.listen(3000);
The trick is leaving this line as last fallback
server.use(express.static(__dirname + '/public'));
As for documentation, since Express uses connect middleware, I found it easier to just look at the connect source code directly.
For example this line shows that index.html is supported
https://github.com/senchalabs/connect/blob/2.3.3/lib/middleware/static.js#L140
In the newest version of express the "createServer" is deprecated. This example works for me:
var express = require('express');
var app = express();
var path = require('path');
//app.use(express.static(__dirname)); // Current directory is root
app.use(express.static(path.join(__dirname, 'public'))); // "public" off of current is root
app.listen(80);
console.log('Listening on port 80');
express.static() expects the first parameter to be a path of a directory, not a filename. I would suggest creating another subdirectory to contain your index.html and use that.
Serving static files in Express documentation, or more detailed serve-static documentation, including the default behavior of serving index.html:
By default this module will send “index.html” files in response to a request on a directory. To disable this set false or to supply a new index pass a string or an array in preferred order.
res.sendFile & express.static both will work for this
var express = require('express');
var app = express();
var path = require('path');
var public = path.join(__dirname, 'public');
// viewed at http://localhost:8080
app.get('/', function(req, res) {
res.sendFile(path.join(public, 'index.html'));
});
app.use('/', express.static(public));
app.listen(8080);
Where public is the folder in which the client side code is
As suggested by #ATOzTOA and clarified by #Vozzie, path.join takes the paths to join as arguments, the + passes a single argument to path.
const path = require('path');
const express = require('express');
const app = new express();
app.use(express.static('/media'));
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'media/page/', 'index.html'));
});
app.listen(4000, () => {
console.log('App listening on port 4000')
})
If you have a complicated folder structure, such as
- application
- assets
- images
- profile.jpg
- web
- server
- index.js
If you want to serve assets/images from index.js
app.use('/images', express.static(path.join(__dirname, '..', 'assets', 'images')))
To view from your browser
http://localhost:4000/images/profile.jpg
If you need more clarification comment, I'll elaborate.
use below inside your app.js
app.use(express.static('folderName'));
(folderName is folder which has files) - remember these assets are accessed direct through server path (i.e. http://localhost:3000/abc.png (where as abc.png is inside folderName folder)
npm install serve-index
var express = require('express')
var serveIndex = require('serve-index')
var path = require('path')
var serveStatic = require('serve-static')
var app = express()
var port = process.env.PORT || 3000;
/**for files */
app.use(serveStatic(path.join(__dirname, 'public')));
/**for directory */
app.use('/', express.static('public'), serveIndex('public', {'icons': true}))
// Listen
app.listen(port, function () {
console.log('listening on port:',+ port );
})
I would add something that is on the express docs, and it's sometimes misread in tutorials or others.
app.use(mountpoint, middleware)
mountpoint is a virtual path, it is not in the filesystem (even if it actually exists). The mountpoint for the middleware is the app.js folder.
Now
app.use('/static', express.static('public')`
will send files with path /static/hell/meow/a.js to /public/hell/meow/a.js
This is the error in my case when I provide links to HTML files.
before:
<link rel="stylesheet" href="/public/style.css">
After:
<link rel="stylesheet" href="/style.css">
I just removed the static directory path from the link and the error is gone. This solves my error one thing more don't forget to put this line where you are creating the server.
var path = require('path');
app.use(serveStatic(path.join(__dirname, 'public')));
You can achieve this by just passing the second parameter express.static() method to specify index files in the folder
const express = require('express');
const app = new express();
app.use(express.static('/media'), { index: 'whatever.html' })

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

Why am I getting "name undefined" when trying to post using Express and Body Parser

I'm attempting to build a MEAN app and trying to test POSTing with POSTMAN. When I do, I keep getting the dreaded "TypeError: Cannot read property 'name' of undefined". If I type in a simple string, the POST goes through fine. But when I use "req.body.name" I get the error. I've looked in every place and I'm not seeing my mistake. I even followed the suggestions on this thread with no luck. Any help or suggestions would be greatly appreciated.
Here's the code I am currently working with in my server.js file:
const express = require('express');
var bodyParser = require('body-parser');
var Bear = require('./models/bear')
var path = require('path');
var mongoose = require('mongoose');
var router = express.Router();
var app = express();
var staticAssets = __dirname + '/public';
app.use(express.static(staticAssets));
app.use('/api', router)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Routes for my API
//===================================
// middleware to use for all requests
router.use(function(req,res,next){
// logging happens here
console.log('Something will happen.');
next(); // Head to the next router...don't stop here
});
// Test router to make sure everything is working (accessed at GET http://localhost:3000/api)
router.get('/', function(req, res){
res.json({message: 'hooray! welcome to our api!'})
})
//More routes will happen here with routes that end in "/bears"
router.route('/bears')
//Create a bear (accessed at POST http://localhost:3000/api/bears)
.post(function(req,res){
var bear = new Bear(); // Create a new instance of the bear model
console.log(req);
bear.name = req.body.name; // set the bears name (comes from the request)
//res.send(200, req.body);
bear.save(function(err){
if (err)
res.send(err);
res.json({message: 'Bear Created!!'});
});
});
//======================================
//var Products = require('./products.model.js');
var Product = require('./models/product.model');
var db = 'mongodb://localhost/27017';
mongoose.connect(db);
var server = app.listen(3000);
console.log("App is listening on port 3000");
Thanks.
Also, the url I'm trying to use inside of POSTMAN is http://localhost:3000/api/bears
Express processes requests Top-Down, meaning if you require a piece of functionality to be applied to all routes via middleware, than that middleware needs to be added to your app before any routes that require it. This is usually the case for middleware such as body-parser.
When using Router Middleware, you don't typically construct the router in the same file as the actual Express app that will use it as middleware. Instead, place it in a separate file and/or directory for organization purposes, this is considered a best practice.
Express Apps can be structured like so
/lib
/models
bear.js
product.js
/node_modules
/public
/css
/routes
api.js
package.json
server.js
The routes directory is where you would place any applicable Router Middleware files such as your api router. server.js is your main Express App and public is where your static assets are stored. lib is directory that contains any business logic files and models.
The actual Express app and Router files should look something like this
server.js
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const apiRouter = require('./routes/api');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, public)));
app.use(/api, apiRouter);
app.listen(port, () => {
console.log(`Listening on port ${port});
});
module.exports = app;
routes/api.js
'use strict';
const router = require('express').Router();
const Bear = require('./lib/models/bear');
router.use((req, res, next) => {
// logging happens here
console.log('Something will happen.');
next(); // Head to the next router...don't stop here
});
router.get('/', (req, res) => {
return res.json({ message: 'hooray! welcome to our api!'})
});
router.route('/bears')
//Create a bear (accessed at POST http://localhost:3000/api/bears)
.post((req, res) => {
var bear = new Bear(); // Create a new instance of the bear model
console.log(req);
bear.name = req.body.name; // set the bears name (comes from the request)
//res.send(200, req.body);
bear.save((err) => {
if (err)
return res.send(err);
return res.json({message: 'Bear Created!!'});
});
});
module.exports = router;
To note, you could break up your API even further to increase the amount of decoupling. An example of this would be to move the /api/bear route to its own router middleware and into its own route file. Then simply add it to your routes/api.js router as a middleware like you would in server.js. If your app is going to have a decent sized API, then this would be the best approach because it would allow the most flexibility when it comes to applying middleware to only certain routes and would make maintaining the source much easier.

Categories