Nodejs/Expressjs app structure - javascript

Say i have this code to separate routes in expressjs:
module.exports = function(express,app,client) {
app.get('/', function(req,res,next) {
var query = 'SELECT * FROM users LIMIT 10';
var user = client.query(query, function (err, results, fields) {
res.render('index', {
title: 'test',
users: results
});
client.end();
});
});
}
And require it in app.js:
require('./controllers/routes.js')(express,app,client);
1) How do i separate db queries into new files in the best way?
This file would get pretty big even if i separate db logic.
2) What is a good way to separate routes? Maybe separate modules? and then require them all in app.js?

There is a similar question here which you should read: How to structure a express.js application?
1) All your query logic should be put in models (modules that reside in /models for example)
2) Separate all your routes (controllers) into modules (and put them in /routes for ex)
By routes I mean for example:
- all the logic for "Users" routes go into /routes/users.js
Try to keep you app as MVC-ish as possible.
Small example for your app above:
app.js
// configuration for express etc
require('./routes/index')(app)
routes/index.js
var model = require("../models/users.js");
module.exports = function (app) {
app.get('/', function (req, res, next) {
model.get_recent(function (err, results) {
// do stuff with your results
res.render('index');
});
});
}
models/users.js
module.exports = {
get_recent: function(callback) {
var query = "SELECT * FROM users LIMIT 10";
database.query(query, callback);
}
}

In the expressjs download package, there is a folder called "mvc". The author provides a good example for a tiny&efficient mvc structure. Going through the code, you will get much inspiration.

How about express-train ? i have been using it lately, and it plays well with complex app structures.

Related

favicon.ico passed as url param in node

I'm starting to learn Node.
I am trying to make a RESTful API for a books app with MySQL, so in my Books.js file I have the following code:
(I am using esm to enable import/exports)
import express from 'express';
import mysqlConnection from '../database';
const router = express.Router()
router.get('/', (req,res) => {
mysqlConnection.query('SELECT * FROM book', (err, rows, fields) => {
if(!err){
res.json(rows);
} else{
console.log(err);
}
})
});
router.get('/:id', (req, res)=> {
const {id} = req.params;
console.log('id is:',id);
mysqlConnection.query(`SELECT * FROM book WHERE isbn ='${id}'`, (err, rows, fields)=> {
if(!err){
res.json(rows);
} else{
console.log(err);
}
})
})
export default router;
And when I go to "http://localhost:3000/123-456-789-13" for example, I get this as logs in the console:
server started!
connected to DB!
id is: 123-456-789-13
id is: favicon.ico
It's not failing but I'm surprised to see this... Any idea of what I'm doing wrong?
Thanks in advance for your answers!
The browser is automatically requesting /favicon.ico to try to get a thumbnail to represent the website.
But, you have a top level wildcard route with:
router.get('/:id', (req, res)=> { ...});
which matches EVERYTHING at the top level, including the request for /favicon.ico. In general, top level wildcard routes like this are a source of trouble because they allow for NO other top level routes anywhere on your site because they match all top level URLs. Not only do they match things like /favicon.ico, but it will also match /robots.txt that search engines may request and it conflicts with you adding other top level routes in the future.
In general, it is recommended that you provide some resource name first such as:
router.get('/book/:id', (req, res)=> { ...});
Then, you won't have any of this conflict with other top level routes.

How to access application-level middleware from router?

I am trying to access my application-level middleware from router in a project generated with express application generator.
Middleware is used to query database with user ID received from router.
I feel like I'm missing something very simple (or fundamental) but can't get around the problem (this being my first Node.js project). So more than best practice I'm looking for a simple solution
I've tried using different app methods including post.
/app.js
var MyAppMidW = function (req, res, next) {
res.send(queryDB(req));
next()
}
app.use(MyAppMidW);
/routes/index.js
router.get("/dbquery", (req, res) => {
if (req.header('auth-header')) {
res.send(req.app.get.MyAppMidW(req.header('auth-header'))); //The problem
}
else {
res.send(req.app.get('defaultData')); //This works
}
});
Error messages include "$middleware is not a function" and "$middleware is not defined".
Solution
/app.js
app.MyAppMidW = function (req) {
queryDB(req);
}
/routes/index.js
router.get("/dbquery", (req, res) => {
if (req.header('auth-header')) {
req.app.MyAppMidW(req.header('auth-header'))); //Makes a database query
res.send(req.app.get('defaultData')); //Fetches database query result
}
else {
res.send(req.app.get('defaultData'));
}
});
If you do it like this
app.use(MyAppMidW);
Every request will query your db, and thats not what you want. I guess you use the MVC design pattern.
In your route folder you have something like this:
import appController from "../controllers/app.js"
router.get("/dbquery", appController.MyAppQuery)
And in your controllers folder you have your logic that querys the db
exports.MyAppQuery = (req, res){
//If u use mongodb for example
YourModel.find().then(data => {
res.json(data)
})
}
You need to call app.set("MyAppMidW", MyAppMidW) and then you can use get. Or do this inside the app.js file
app.MyAppMidW = function (req, res, next) {
res.send(queryDB(req));
next()
}
Then call it by req.app.get('MyAppMidW')(req.header('auth-header')) or req.app.MyAppMidW(req.header('auth-header')) inside the routes file.
But middleware is called automatically when you say app.use(MyAppMidW) the function is called by default on each request. So no need to call it explicitly inside the router function.

How to avoid the ambiguity of routes in Express.js

I have three files server.js, views.js and access.js
In server.jsI have put all the dependencies and some routes like
app.post('/services/getallversions', (req, res) => {
...
// code to handle the req and send response
})
In views.js I have code like below,
module.exports = function(app, db, bodyParser, rules, constants, query) {
app.post('/services/user/:user/:type', (req, res) => {
// user can be 'abcd'
// type can be addview, deleteview etc.
...
// do processing for the req and send res
})
}
In access.js I have code like,
module.exports = function(app, db, bodyParser, rules, constants, query) {
app.post('/services/user/:user/:type', (req, res) => {
// user can be 'abcd'
// type can be addaccess, removeaccess etc.
...
// do processing for the req and send res
})
}
In server.js file I require the access.js and views.js in following way,
var access = require('./access')(app, db, bodyParser, rules, constants, query)
var views = require('./views')(app, db, bodyParser, rules, constants, query)
When I try to POST using /services/user/abcd/addaccess my views.js file code gets executed. constants, query, rules are other .js file which is already used in server.js using require('./filename').
I understand that the ambiguity causes due to same URL structure. I am using Express 4 and Node JS 6. I want to separate code of access.js and views.js from server.js and put them in separate files and require them in the above mentioned manner. views.js and access.js are created by me. They are not any Javascript Framework or something like that.
In view.js I have also tried the following code
var router = require('express').Router()
router.post('/services/user/:user/:type', (req,res)=>{})
But the same problem exists. Is there any way to achieve the thing ?
I suggest you use "miniApp" concept in Express, where each "miniApp" is distinguished using name-space.
For example:
Main App:
All routes with '/views/...' prefix will go to viewsCtrl. This middleware should appear before your default/main app routes:
var viewsCtrl = require('./views');
app.use('/views', viewsCtrl);
Inside views.js:
var router = require('express').Router();
// complete route /views/services/user/:user/:type
router.get('/services/user/:user/:type', function(req, res){...});
module.exports = router;
Same for access.js.
The routes are identical and express will never be able to tell which one to call. Order is not the problem here; as Chris G said in his comment, the second call to app.post(...) will overwrite the first (think of URLs as keys in a hashset).
You already know that the url will be in the format of /addview or /removaccess etc, so you can put that knowledge in the routing middleware:
// access.js
app.post('/services/user/:user/access/:type', (req, res) => {
// ... type is now only add, remove, etc...
})
// view.js
app.post('/services/user/:user/view/:type', (req, res) => {
// ...
})
or even (I think):
// access.js
app.post('/services/user/:user/:type((access)$)/', (req, res) => {
// ... will match addaccess, removeaccess and so on
// but I'm not entirely sure ...
})
Reference here:
https://expressjs.com/en/guide/routing.html

How to post data from module.exports in node.js

I am trying to take a user input and save it to a collection in my database. I am using Node.js, mongodb, mongoose, express.js and ajax.
I am currently trying to take the post when the user submits the form and take the input and save it to my data base from inside of my module.exports in my controller file.
I was able to make this work when all of the code was in one place inside the server.js but in an attempt to break my code apart appropriately I am trying to separate into a MVC system.
My addProductGroup controller looks like this:
//bring in models of data
var groups = require('../models').Groups;
var express = require('express');
var app = express();
//page functions go inside of module.exports
module.exports = {
index: function(req, res){
groups.find({}, function(err, groups){
if(err){
console.log(err);
}else{
res.render('addProductGroup',{title: 'Admin Add Group', adminloggedin: true, subtitle: 'Add a Group', underheaderp: ''});
app.post('/admin/addProductGroup', function(req,res){
var newGroupName = req.body.groupname;
new groupName({
groupName: req.body.groupname,
}).save(function(err, doc){
if(err){
res.json(err)
}
else {
res.render('addProductGroup',{title: 'Admin ASS Group', adminloggedin: true, subtitle: 'Add a Group', underheaderp: ''});
}
});
});
}
});
}
}
My controller is getting my data from my groups collection and then rendering my page. Then when the user posts the data I am trying to make it take the post data, save it to my database and then render the same exact page. I have played a lot with the nesting of my functions and order of operations.
My groups.js Model :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var GroupsSchema = new Schema ({
groupName: String
});
module.exports = mongoose.model('groups', GroupsSchema);
var groupName = module.exports;
I am using a handlebars template for my views.
So is having all of this in my module.exports a possible thing to accomplish?
Do i need to try and write a function outside of my module.exports to make this work?
If you need to see any of my other files just let me know.
Any help is greatly appreciated.
You do not clarify the issue you have, so I will try to provide you some general help:
Concerning organizing your express application you definitly should take a look at the Version 4 introduced Routers.
You can bind your routes directly on the router object and so seperate your logic into different files (modules).
Your party.js router could look like:
var express = require('express').Router()
router.get('/paricipants', function(req, res) {
res.send('dave','mike')
})
module.exports = router
You can have several such routers (controllers) in your controllers directory (i.e. /controllers). Taking full advantage of the module.exports functionality, you may now put an index.js file in this directory, which then will be loaded by default, as you require the directory.
Your index.js file in your controllers directory could look like:
var router = require('express').Router()
router.use('/party', require('./party'))
// Your other routes to controllers and eventually global routes here.
module.exports = router
You can then simply require this one module in your app.js:
var app = express()
app.use(require('./controllers'))
...
Now just require your mongoose models inside your controllers as you need them.
This will give you a more modular and structured application design.
Hope it helps.

Dynamic routing with express framework in node

I'm using express framework 4.0 for my node js server . I was wondering if there was any way to remove routes dynamically at runtime
var express = require('express');
var router = express.Router(/*Options */);
router.get('/', function (req, res)
{
res.render('index', {title: "Home"});
});
router.get('/features', function (req, res)
{
res.render('features', {title: "Features"});
});
//Hook into the routing system
module.exports = function(app,rootPath)
{
app.use(rootPath, router);
};
This is a trivial example, but how could I remove the /features path from the routing table?Additionally is it possible to overwrite this routing path with another should I wish to update the features routing path at a later date ?
AFAIK you can't delete a route dynamically (at least not in a nice way), but you can use a filtering middleware to disallow access to a route when a certain condition is set.
For example:
var allowRoute = true;
var filterMiddleware = function(req, res, next) {
if (allowRoute !== true) {
return res.status(404).end();
}
next();
};
app.get('/features', filterMiddleware, function(req, res) {
res.render('features', { title: 'Features' });
});
You toggle allowRoute to enable or disable access to the route (obviously, depending on the exact use case you could also use properties in req to enable/disable access to the route).
A similar setup could be used to overwrite the route handler with another one, although I'm beginning to wonder what you are trying to accomplish and if overwriting route handlers is the solution for that.

Categories

Resources