How do I modularize my Node.js, express project? - node.js

I have created a API for different webpages with some CRUD functionality for POST, GET, etc. methods using Node.js, express and mongoose. I also have a big app.js file, where my routing logic and functions for CRUD methods reside.
So in the app.js file, I have to do the CRUD functionality and routing logic for every model in my models folder. This is quite much for on file, how can I separate the CRUD logic for my models, and the routing logic? So that it still works as normal without hosing my file?
I was thinking to separate the CRUD into a "controllers" folder and the routing into the "routes" folder, but I dont know how exactly, and what to require at what place..
My app.js looks like:
var express = require('express');
var app = express();
var bodyParser = require("body-parser");
var morgan = require("morgan");
var routes = require('./routes');
var cors = require('cors')
//configure app
app.use(morgan('dev')); //log requests to the console
//configure body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 5000;
//DATABASE SETUP
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/DNZ'); //connect to uor datbaase
//Handle the connection event, get reference to database.
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log("DB connection alive");
});
//DNZ models live here
var FA = require('./models/DNZmodels/FA');
var FP = require('./models/DNZmodels/FP');
//ROUTES FOR OUR API
//=============================================================================
//create our router
var router = express.Router();
//middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
console.log('Today is:', Date())
next();
});
//test route to make sure everything is working (accessed at GET http://localhost:5000/DNZ/)
router.get('/', function(req, res) {
res.json({ message: 'Welcome to DNZ API!' });
});
//on routes that end in /FA
//----------------------------------------------------
router.route('/FA')
// create a FA (accessed at POST http://localhost:8080/DNZ/FA)
.post(function(req, res) {
//console.log(req.body);
//console.log(req.body.params);
//res.setHeader('Content-Type', 'application/json')
//res.send(JSON.stringify(req.body));
/*
var timestamp = req.body.Timestamp;
var prognostizierterBetriebswert = req.body.PrognostizierterBetriebswert;
var posFlexPot = req.body.posFlexPot;
var negFlexPot = req.body.negFlexPot;
var leistungsuntergrenze = req.body.Leistungsuntergrenze;
var leistungsobergrenze = req.body.Leistungsobergrenze;
var posGesEnergie = req.body.posGesEnergie;
var negGesEnergie = req.body.negGesEnergie;
var preissignal = req.body.Preissignal;
var dummy1 = req.body.Dummy1;
var dummy2 = req.body.Dummy2;
var dummy3 = req.body.Dummy3;
var fa = new FA({
Timestamp: timestamp,
Leistungsuntergrenze: leistungsuntergrenze,
Leistungsobergrenze:leistungsobergrenze,
PrognostizierterBetriebswert :prognostizierterBetriebswert,
posFlexPot: posFlexPot,
negFlexPot:negFlexPot,
posGesEnergie: posGesEnergie,
negGesEnergie: negGesEnergie,
Preissignal:preissignal,
Dummy1: dummy1,
Dummy2: dummy2,
Dummy3: dummy3
})
*/
//fa.name = req.body.name;
console.log("Erzeugen der Instanz FA..");
//console.log(Dummy1);
//res.send(JSON.stringify(timestamp));
// create a new instance of the FA model
var fa = new FA(req.body);
//SAVE the new instance
fa.save(function(err) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("Instanz FA in Datenbank erzeugt!");
res.status(200);
res.json({ message: 'FA-Instance created in datbase!' });
}
});
})
// get all the FAs (accessed at GET http://localhost:8080/DNZ/FA)
.get(function(req, res) {
FA.find(function(err, fas) {
if (err)
res.send(err);
res.json(fas);
});
});
//on routes that end in /FA/:FA_id
//----------------------------------------------------
router.route('/FA/:FA_id')
// get the bear with that id
.get(function(req, res) {
FA.findById(req.params.bear_id, function(err, fa) {
if (err)
res.send(err);
res.json(fa);
});
})
/*
* Athlete.
find().
where('sport').equals('Tennis').
where('age').gt(17).lt(50). //Additional where query
limit(5).
sort({ age: -1 }).
select('name age').
exec(callback);
*/
// update the bear with this id
.put(function(req, res) {
FA.findById(req.params.FA_id, function(err, fa) {
if (err)
res.send(fa);
//bear.name = req.body.name;
/*
FA.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'FA updated!' });
});
*/
});
});
/*
// delete the bear with this id
.delete(function(req, res) {
FA.remove({
_id: req.params.bear_id
}, function(err, FA) {
if (err)
res.send(err);
res.json({ message: 'Successfully deleted' });
});
});
*/
//*************************************************************************
//CREATE FP ROUTE
//*************************************************************************
router.route('/FP')
// create a FA (accessed at POST http://localhost:8080/DNZ/FP)
.post(function(req, res) {
//res.setHeader('Content-Type', 'application/json')
console.log("Erzeugen der Instanz FP..");
// create a new instance of the FP model
var fp = new FP(req.body);
//SAVE the new instance
fp.save(function(err) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("Instanz FP in Datenbank erzeugt!");
res.status(200);
res.json({ message: 'FP-Instance created in datbase!' });
}
});
})
// get all the FAs (accessed at GET http://localhost:8080/DNZ/FA)
.get(function(req, res) {
FP.find(function(err, fps) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
//res.send("Willkommen auf /FP");
res.json(fps);
}
});
});
//REGISTER OUR ROUTES -------------------------------and listen to requests
app.use('/DNZ', router);
//START THE SERVER
//=============================================================================
// set static directories
app.use(express.static('./dist'));
app.use(cors());
// Define Routes
var index = require('./routes/index');
var users = require('./routes/users');
//Set up routes
routes.init(app)
//run
app.listen(port);
console.log('Listen on port: ' + port);
console.log('Server started, Listening on port ', port);

This is primarily opinion based, but I had the same thing a while back and developed a way to extract route/model logic from the main file, using the module require-dir
In my app.js
/**
* Process ALL routes from routes dir utilising require-dir
*
* Allows us to include an entire directory, without replicating
* code, creating similar routes on a per end-point basis. This
* nicely keeps all end-point routes separate.
*/
var routes = requireDir('./routes');
for(var x in routes) {
application.use('/', routes[x]); // here, application is your express server instance
}
Then create a directory called routes and add whatever, for instance routes/branding.js:
var expressFramework = require('express');
var Branding = require('../models/branding');
var responseHelper = require('../shared/responseHelper');
var responseStatusCodes = require('../shared/responseStatusCodes');
var responseMessages = require('../shared/responseMessages');
var queryHelper = require('../shared/queryHelper');
var routerObject = expressFramework.Router();
var branding = new Branding();
var responsehelper = new responseHelper();
var queryhelper = new queryHelper();
/**
* Endpoint /branding/{chain_id}/{site_id}
*/
routerObject.get('/branding/:chain_id/:site_id', function(req, res, next) {
var requiredFields = [
{
chain_id: true, where: 'path'
},
{
site_id: true, where: 'path'
}
];
if (!queryhelper.authenticateToken(req.headers.authorization)) {
responsehelper.sendResponse(res, responseStatusCodes.STATUS_UNAUTHORISED,
responseMessages.RESPONSE_AUTHENTICATION_FAILED);
return;
}
if (!queryhelper.validateQuery(req, requiredFields)) {
responsehelper.sendResponse(res, responseStatusCodes.STATUS_INVALID_QUERY_PARAMS,
responseMessages.RESPONSE_INVALID_QUERY_PARAMS);
return;
}
branding.getBranding(req, function(err, results, pagination) {
if (err) return next(err);
if (results.length >= 1) {
responsehelper.sendResponse(res, responseStatusCodes.STATUS_OK, results);
} else {
responsehelper.sendResponse(res, responseStatusCodes.STATUS_NOT_FOUND,
responseMessages.RESPONSE_NO_RECORDS_FOUND);
}
});
});
module.exports = routerObject;
The key point here, is that you eventually export the express Router object, which your application, can 'use'. You'll also notice, that branding uses an include var Branding = require('../models/branding'); - This contains all the logic, whereas the route contains the end point definitions only, a snippet:
var Promise = require('bluebird');
var db = require('../shared/db');
var queryHelper = require('../shared/queryHelper');
var schemas = require('../schemas/schemas');
var _ = require('lodash');
var serverSettings = require('../shared/coreServerSettings');
// Create new instance of mysql module
var connection = new db();
var queryhelper = new queryHelper();
var queryAndWait = Promise.promisify(connection.query);
// Branding Object
var Branding = function(data) {
this.data = data;
};
Branding.prototype.data = {};
/**
* Branding methods
*/
Branding.prototype.getBranding = function(req, callback) {
var params = [];
var queryFoundRows = `select FOUND_ROWS() as total`;
var query = `select
id
from
company
where
1=1
and chain_id=?`;
params.push(req.params.chain_id);
queryAndWait(query + '; ' + queryFoundRows, params).then(function(result) {
return Promise.map(result[0], function(row) {
var params = [];
var query = `select
*
from
location
where
1=1
and company_id=?
and site_id=?`;
params.push(row.id);
params.push(req.params.site_id);
return queryAndWait(query, params).then(function(result) {
return result[0];
});
}).then(function(payload) {
callback(null, payload);
}).catch(function(err) {
callback(err, null, null);
});
});
};
module.exports = Branding;
May not be exactly what you're after, but should provide a good start point. Good luck!

This topic is subjective however - it is important to take a standard and stick to it. The way I handled this was by creating a subfolder with a module (using module.exports) and an init function that constructs the express app.
For every route I have another module that has an init function which accepts the express application as a parameter and then adds the routes in there.
Main code file:
var Api = require('./API/index.js');
File /API/Index.js:
var express = require('express');
/* Instantiations */
var app = express();
module.exports = {
...
apply();
...
}
var route1 = require('./Routes/route1.js');
var route2 = require('./Routes/route2.js');
/* all additional routes */
var Routes = [route1,route2,...]
function apply(){
for(var i=0;i<Routes.length;i++){
Routes[i].init(app);
}
}
Then in API/Routes/route1.js and API/Routes/route2.js...
module.exports = {
init: function(app){
/* add your route logic here */
}
}
The benefits of this approach in my experience is that you can optionally choose to add or remove routes as needed and it provides a readable route-path via the file system which is handy in most modern text editors.

Related

Router.express() -> What is the proper way for expressing router.use?

For router.use, it does not work like this anymore:
router.use("/api", apiRoutes);
Instead an error is thrown:
throw new typeerror('router.use() requires a middleware function but got a ' + gettype(fn))
How do I re-purpose that expression so that it works? I have not found any examples that were useful so far. Here is some of my sample code:
routes/index.js (this does not work)
const path = require("path");
const router = require("express").Router();
const apiRoutes = require("./api");
// API Routes
router.use("/api", apiRoutes);**// this throws an error**
router.use(function(req, res) {
res.sendFile(path.join(__dirname, "../client/build/index.html"));
});
module.exports = router;
Here is an example of my attempt to re-purpose but I do not think it's correct:
var path = require("path");
var router = require("express").Router();
var apiRoutes = require("./api");
//API Routes
//authRouter.use(require('./authenticate').basic(usersdb))
//router.use("./api", apiRoutes);
console.log("Hitting API routes...")
router.use("./api", function(req, res, next) { **//re-purpsose attempt here**
res.send(apiRoutes)
console.log("API Routes:", apiRoutes)
next()
});
console.log("API Routes hit")
// //If no API routes are hit, send the React app
// router.use(function(req, res) {
// res.sendFile(path.join(__dirname, "../client/public/index.html"));
// });
module.exports = router
This is the overall error I'm getting (404 returned):
GET /api/website_1_function_call/scrape 404 4.004 ms - 173
I know that this may be due to something else indirectly but I really am not sure about the router.use part.
I know for sure that the routes are not being hit properly and would like to fix.
Any advice would be appreciated. Thank you in advance.
Here is more code:
server.js
require("dotenv").config();
var express = require("express");
var cors = require('cors');
var bodyParser = require('body-parser');
var logger = require("morgan");
//const mongoose = require("mongoose");
var db = require("./models")
var routes = require("./routes");
var app = express();
var PORT = process.env.PORT || 3001;
var path = require('path');
//Define middleware here
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(bodyParser.json());
//Serve up static assets (usually on heroku)
if (process.env.NODE_ENV === 'production') {
app.use(express.static("client/build"));
}
app.use(cors());
app.use(logger("dev"));
//Add routes, both API and view
app.use(routes);
//replaced with below:
//app.use(app.router);
//routes.initialize(app);
// //Connect to the Mongo DB
// mongoose.connect(process.env.MONGODB_URI || "mongodb://localhost/kaibru");
var syncOptions = { force: false };
// If running a test, set syncOptions.force to true
// clearing the `testdb`
if (process.env.NODE_ENV === "test") {
syncOptions.force = true;
};
// Starting the server, syncing our models ------------------------------------/
db.sequelize.sync(syncOptions).then(function() {
app.listen(PORT, function() {
console.log(
"==> 🌎 Listening on port %s. Visit http://localhost:%s/ in your browser.",
PORT,
PORT
);
});
});
// //Start the API server
// app.listen(PORT, function() {
// console.log(`🌎 ==> API Server now listening on PORT ${PORT}!`);
// });
routes/index.js
var path = require("path");
var router = require("express").Router();
var apiRoutes = require("./api");
//API Routes
//authRouter.use(require('./authenticate').basic(usersdb))
//router.use("/api", apiRoutes);
console.log("Hitting API routes...")
router.use("/api", function(req, res, next) { // this is my re-purpose
attempt
apiRoutes
console.log("API Routes:", apiRoutes)
// next()
}); // this is my r-purpose attempt
console.log("API Routes hit")
// //If no API routes are hit, send the React app
// router.use(function(req, res) {
// res.sendFile(path.join(__dirname, "../client/public/index.html"));
// });
module.exports = router
routes/api/index.js
var router = require("express").Router();
require("./website_1");
var website_1Routes = require("./website_1_function_call");
//const userRoutes = require("./user");
//Website_1 routes
//http://localhost:3000/api/website_1_function_call/scrape
//authRouter.use(require('./authenticate').basic(usersdb))
//router.use("/website_1_function_call", website_1Routes);
//experimental use
router.use("/website_1_function_call", function(req, res, next) { // this is my re-purpose attempt
website_1Routes
console.log("website_1Routes:", website_1Routes)
// next()
}); //this is my re-purpose attempt
//router.use("/user", userRoutes);
module.exports = router
routes/api/website_1_function_call.js
require("./website_1");
require("./website_1_db");
require("./website_1_router");
//Call scrape functions from website_1 file
mainscrape();
//specificScrape() //let's leave this one dormant for now
//Now for saving to database
saveToDatabase();
//Now for the routes
routing();
I think my re-purpose attempt worked ( I removed next() since there are no defined routes right after). It seems to be processing. However, now my response hangs and this happens:
GET /api/website_1_function_call/scrape - - ms - -
This prints in the browser console:
GET http://localhost:3000/api/website_1_function_call/scrape
net::ERR_EMPTY_RESPONSE
0.chunk.js:871 Uncaught (in promise) Error: Network Error
at createError (0.chunk.js:871)
at XMLHttpRequest.handleError (0.chunk.js:366)
So now I think my scraper code and my code to update the database does not work.
Scrape function code:
//var express = require("express");
var router = require("express").Router();
require("../../controllers/website_1controller");
//requiring this website's models
var Items_1 = require("../../models/website_1");
//require("./website_1_db");
//require("./website_1_router");
// Our scraping tools
// Axios is a promised-based http library, similar to jQuery's Ajax method
// It works on the client and on the server
var axios = require("axios");
var cheerio = require("cheerio");
mainscrape = function() {
//Now to configure the routes
router.get("/scrape", function(req, res) {
//instead of simple res.render, user router.get
console.log("scraping started...");
//Grab the html body with axios
axios.get("url placeholder").then(function(response) {
//Load to cheerio and save to $ selector
console.log("Scraping all greenheartshop mainpage...");
var $ = cheerio.load(response.data);
var output = [];
var promises = [];
//Now we need to grab the title reference for each article
$("article").each(function(i, element) {
//save empty result object
var result = {};
//thumbnail
result.thumbnail = $(this)
//.children("article.product-grid-item.product-block").html()
.children("figure.product-item-thumbnail")
.children("a")
.attr("href")
//console.log("result thumbnail")
//console.log(result)
console.log(result.thumbnail)
var result = {}
//details
result.detail= $(this)
//.children("product-item-mask").html()
.children("div.product-item-details")
// .children("div.product-item-brand")
// .children("h5.product-item-title")
// .children("a")
// .children("div.product-item-price")
//.children("product-price-line")
//.children("price-value")
.text()
//result.detail = result.detail.trim();
//console.log("result detail")
//console.log(result)
console.log(result.detail)
//Capture the scraped data and save to database
console.log("Capturing Scrape")
if(result.detail !== '') {
var promise = Items_1
.saveToDatabase(result, result, {upsert:true, new:true})
console.log("saveToDatabase");
promises.push(promise);
}
Promise.all(promises).then((data) => {
res.json(data);
});
//saveToDatabase();
// if (result.thumbnail !== {} && result.detail !== "") {
// var promise = Items_1
// // .items_1_create({
// // resultThumbnail: result.thumbnail,
// // resultDetails: result.detail
// // })
// promises.push(promise)
// // .then(dbModel => output.push(dbModel));
// Promise.all(promises).then((data) => {
// res.json(data)
// })
// }
});
});
//Now to CREATE the results using controller file
// console.log("creating items in the database now...")
// router.post('/scrape', website_1Controller.items_1_create);
//Now to display the results
// console.log("Items now being displayed...")
// router.get('/scrape/display', website_1Controller.items_1_list)
});
}
module.exports = router;
module.exports = mainscrape;
module.exports = specificScrape;
Code to update the database:
require("../../controllers/website_1controller");
require("./website_1");
var Items_1 = require( "../../models");
//After scraping the main page, the following function is to save to the
database
saveToDatabase = function() {
//prepare the data
var result = {}
var dataToStore = Items_1.items_1_create
console.log(dataToStore)
//console.log(items_1_create)
//insert data to the database
// dataToStore.save().// We will not sue this part for now
// then(() => {
// console.log("Data successfully saved");
// }).catch(err => {
// console.log("Error: ", err);
// });
}
module.exports = saveToDatabase;
Code for final routing (after scrape is complete)
var website_1Controller = require("../../controllers/website_1controller");
var router = require("express").Router();
routing = function() {
//Now to CREATE the results using controller file
console.log("creating items in the database now...")
//router.route("/browse")
router.post('/browse', website_1Controller.items_1_create);
router.get('/browse', website_1Controller.items_1_list);
//Now to display the results
console.log("Items now being displayed...")
//router.route("/browse:search")
router.get('/:search', website_1Controller.items_1_specific);
};
require("./website_1");
module.exports = routing;
module.exports = router;
models
'use strict';
// Dependencies
// =============================================================
// Sequelize (capital) references the standard library
//var Sequelize = require("sequelize");
// sequelize (lowercase) references our connection to the DB.
//var sequelize = require("../config/connection.js");
// Creates a "Items_1" model that matches up with DB
module.exports = function(sequelize, DataTypes) {
var Items_1 = sequelize.define("Items_1", {
// the routeName gets saved as a string
detail: DataTypes.STRING,
// the name of the character (a string)
thumbnail: DataTypes.BLOB,
// the character's role (a string)
//role: Sequelize.STRING,
// the character's age (a string)
//age: Sequelize.INTEGER,
// and the character's force points (an int)
//forcePoints: Sequelize.INTEGER
}, {
// disable the modification of tablenames; By default, sequelize will
automatically
// transform all passed model names (first parameter of define) into
plural.
// if you don't want that, set the following
freezeTableName: true
});
return Items_1;
//Syncs with DB
//Items_1.sync();
// Makes the Items_1 Model available for other files (will also create a table)
};
controller
// *********************************************************************************
// website_1controllers.js - this file offers a set of routes for displaying and saving data to the db
// *********************************************************************************
// Dependencies
// =============================================================
var db = require("../models");
//display results for mainpage scrape
exports.items_1_create = function(req, res) {
db.Items_1.findOneAndUpdate(req.body, req.body, {upsert: true, new:
true})
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err))
console.log("findOneAndUpdate complete")
},
exports.items_1_list = function(req,res) {
db.Items_1.findAll({})
},
exports.items_1_specific = function(req,res) {
db.Items_1.findById(req.params.search)
},
function(err, results) {
if (err) { return next(err); } //Error in API usage.
if (results.result.thumbnail==={} && results.result.detail==="") {//No
Results.
var err = new Error('Results not found');
err.status = 404;
return next(err)
}
//Successful, so render
res.render("click_results", { title: 'Click Results', resultThumbnail:
result.thumbnail, resultDetails: result.detail });
}
So the new issue is that the response hangs. I think it's because the code to update the database does not work (using sequelize). Let me know if anything else is needed and thank you in advance.
Thanks for all of the input everyone. After reviewing I found out that the function itself does not have to be re-purposed as I initially thought... I didn't know that if, for example, you are using "router.use("/directoy", directory) and you are using it in succession to point to different directories, the final directory hit must have a defined route like router.get(). I modularized my code to the point where the final directory was just a list of functions (one of these functions had the router.get method). This did not work. When I point the file directly to the code containing the router.get method, my scraped data returns to the terminal. Just thought I'd share my findings at least because I didn't know this at all . Many thanks to #mehta-rohan and #Anand Undavia for the insights. I'm still trying to get the data to render to the page but that's a different problem altogether.

MEAN API using node-restful no response

I'm trying to setup API for multiple projects that use same database structure (running on same CMS) but when I'm trying to reach some data I get no response.
index.js
var express = require("express");
var cors = require("cors");
var mongoose = require("mongoose");
var bodyParser = require("body-parser");
var methodOverride = require("method-override");
var _ = require("lodash");
var passport = require("passport");
var dbconfig = require("./app/config/database");
// Create the application
var app = express();
var user = require("./app/routes/User");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(methodOverride('X-HTTP-Method-Override'));
var connections = [];
// Auto CORS
app.use(cors());
/* Mnual CORS Start
app.use(function(req, res, next){
res.header("Access-Controll-Allow-Origin", "*");
res.header("Access-Controll-Allow-Methods", "GET,PUT,POST,DELETE");
res.header("Access-Controll-Allow-Headers", "Content-Type");
next();
});
/* Manual Cords end */
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
require("./app/config/passport")(passport);
app.get("/", (req, res) => {
res.json({ msg: "Nothing here mate" });
});
//------------ THIS IS WORKING ----------------
app.get("/db/:database/navigation", (req, res) => {
var dbname = req.params.database;
var conn = connections[dbname];
var navs = conn.model("navigation", app.models[dbname].navigation);
// Send json data/error
if (navs) navs.find({}, (err, data) => res.json(data));
else res.json({ error: true, msg: "Model not found" });
});
// -------------------------------------------------------
// Setup databases for all projects
_.each(dbconfig.databases, db => {
var appModels = require("./app/models/index");
var processed = 0;
// We will use prefix for all routes /db/:database/
var routePrefix = "/db/" + db.name;
// Use user section
app.use(routePrefix + "/user", user);
// Connection callback - we need to wait for modules to initialize
var connect = () => {
// Initialize connection
connections[db.name] = new mongoose.Mongoose().createConnection(db.url);
// Create some callbacks
connections[db.name].on("connected", () => { console.log("Connected to database " + db.url); });
connections[db.name].on("error", onDatabaseError)
// Once we initialize connection, we need to setup all routes
connections[db.name].once("open", function () {
// Load routes
var routes = require('./app/routes');
// Loop trough routes and use all of them
_.each(routes, function (controller, route) {
var newRoute = routePrefix + route;
app.use(newRoute, controller(app, newRoute, db.name));
});
});
};
// Initialize models
_.each(appModels, (model, index) => {
// Create object if doenst exist
if (app.models == null)
app.models = {};
if (app.models[db.name] == null) {
app.models[db.name] = { [model.name]: model.model };
}
else {
app.models[db.name] = Object.assign(app.models[db.name], { [model.name]: model.model });
}
processed++;
// if this was the last process we are ready to connect
if (processed === appModels.length)
connect();
});
});
app.listen(3000);
app/models/index.js
module.exports = [
{
name: "navigation",
model: require('./Navigation.js')
},
...
];
app/routes.js
module.exports = {
'/navigation': require('./controllers/NavigationController'),
....
};
app/controllers/NavigationController.js
var restful = require("node-restful");
module.exports = function(app, route, dbname){
console.log(route);
var rest = restful.model(
"navigation",
app.models[dbname].navigation
).methods(['get', 'put', 'post', 'delete']);
rest.register(app, route);
// Return middleware
return function(req, res, next){
next();
};
};
Navigation.js is basically just a schema. If I set up route manually like this:
app.get("/db/:database/navigation", (req, res) => {
var dbname = req.params.database;
var conn = connections[dbname];
var navs = conn.model("navigation", app.models[dbname].navigation);
// Send json data/error
if (navs) navs.find({}, (err, data) => res.json(data));
else res.json({ error: true, msg: "Model not found" });
});
it works just fine. I guess I need to assign connection somewhere to restful but I have no idea where. If I use single connection with mongoose.connect() everything works perfectly, but that's not what I need :)
Does anyone have any idea what to do next to get this to work? Will appreciate any help, thanks.
Kind of dug into it and made an extension to change driver reference
Here are all the changes, hope it helps someone in future :)
extensions/restful/index.js
var restful = require("node-restful"),
model = require("./model"),
mongoose = require('mongoose');
exports = module.exports = restful;
exports.model = model;
exports.mongoose = mongoose;
extensions/restful/model.js
exports = module.exports = model;
exports.changeDriver = function(driver){
mongoose = driver;
}
// original model function from node-restful/lib/model.js
function model() {
var result = mongoose.model.apply(mongoose, arguments),
default_properties = defaults();
if (1 === arguments.length) return result;
for (var key in default_properties) {
result[key] = default_properties[key];
}
return result;
}
app/controllers/navigation.js
var restful = require("../extensions/restful");
module.exports = function(app, route, db)
{
restful.model.changeDriver(db.mongoose);
// Setup controller REST
var rest = restful.model(
"navigation",
app.models[db.name].navigation
).methods(['get', 'put', 'post', 'delete']);
// Register this endpoint with the application
rest.register(app, route);
// Return middleware
return function(req, res, next){
next();
};
};
index.js
....
var connect = () => {
// Initialize connection
var $db = databases[_db.name] = {
mongoose: new mongoose.Mongoose(),
name: _db.name
};
$db.mongoose.connect(_db.url);
// Create some callbacks
$db.mongoose.connection.on("connected", () => { console.log("Connected to database " + _db.url); });
$db.mongoose.connection.on("error", (err) => { console.log("Database error: " + err); });
// Once we initialize connection, we need to setup all routes
$db.mongoose.connection.once("open", function () {
// Custom routes for user section
var userRoutes = new UserRoutes($db.mongoose);
app.use(routePrefix + "/user", userRoutes.getRouter());
// Load routes
var routes = require('./app/routes');
// Loop trough routes and use all of them
_.each(routes, function (controller, route) {
var newRoute = routePrefix + route;
app.use(newRoute, controller(app, newRoute, $db));
});
});
};
....

Creating MongoDB connection with mongoose

I am desperately trying to create a connection with mongoDB with the MEAN stack, using mongoose.
My MongoDB instance (mongod) is running and I can use mongo.exe and tested it by inserting some documents, it worked fine. But I have problems to create a connection to MongoDB with mongoose, and inserting a document with the .save() method does not work either...
I first wanted to try my POST method, created a function and tested it by creating some values in POSTMAN. But no documents were inserted in my MongoDB datbase..
This is my app.js file:
var express = require('express');
var app = express();
var bodyParser = require("body-parser");
var morgan = require("morgan");
//var routes = require('./routes');
//var cors = require('cors')
//configure app
app.use(morgan('dev')); //log requests to the console
//configure body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 5000;
//DATABASE SETUP
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/DNZ'); //connect to uor datbaase
//Handle the connection event
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log("DB connection alive");
});
//DNZ models live here
var FA = require('./models/DNZmodels/FA');
//ROUTES FOR OUR API
//=============================================================================
//create our router
var router = express.Router();
//middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
console.log('Today is:', Date())
next();
});
//test route to make sure everything is working (accessed at GET http://localhost:5000/DNZ/)
router.get('/', function(req, res) {
res.json({ message: 'Welcome to DNZ API!' });
});
//on routes that end in /FA
//----------------------------------------------------
router.route('/FA')
// create a FA (accessed at POST http://localhost:8080/DNZ/FA)
.post(function(req, res) {
//console.log(req.body);
//console.log(req.body.params);
//res.setHeader('Content-Type', 'application/json')
res.send(JSON.stringify(req.body));
/*
var timestamp = req.body.Timestamp;
var prognostizierterBetriebswert = req.body.PrognostizierterBetriebswert;
var posFlexPot = req.body.posFlexPot;
var negFlexPot = req.body.negFlexPot;
var leistungsuntergrenze = req.body.Leistungsuntergrenze;
var leistungsobergrenze = req.body.Leistungsobergrenze;
var posGesEnergie = req.body.posGesEnergie;
var negGesEnergie = req.body.negGesEnergie;
var preissignal = req.body.Preissignal;
var dummy1 = req.body.Dummy1;
var dummy2 = req.body.Dummy2;
var dummy3 = req.body.Dummy3;
*/
var fa = new FA();
fa.name = req.body.name;
console.log("Hier erscheint var fa:", fa);
//console.log(Dummy1);
//res.send(JSON.stringify(timestamp));
// create a new instance of the FA model
/*
var fa = new FA({
Timestamp: timestamp,
Leistungsuntergrenze: leistungsuntergrenze,
Leistungsobergrenze:leistungsobergrenze,
PrognostizierterBetriebswert :prognostizierterBetriebswert,
posFlexPot: posFlexPot,
negFlexPot:negFlexPot,
posGesEnergie: posGesEnergie,
negGesEnergie: negGesEnergie,
Preissignal:preissignal,
Dummy1: dummy1,
Dummy2: dummy2,
Dummy3: dummy3
})
*/
//SAVE the new instance
fa.save(function(err) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("debug");
res.status(200);
res.json({ message: 'FA created!' });
}
});
})
// get all the FAs (accessed at GET http://localhost:8080/DNZ/FA)
.get(function(req, res) {
FA.find(function(err, fas) {
if (err)
res.send(err);
res.json(fas);
});
});
//on routes that end in /FA/:FA_id
//----------------------------------------------------
router.route('/FA/:FA_id')
// get the bear with that id
.get(function(req, res) {
FA.findById(req.params.bear_id, function(err, fa) {
if (err)
res.send(err);
res.json(fa);
});
})
// update the bear with this id
.put(function(req, res) {
FA.findById(req.params.FA_id, function(err, fa) {
if (err)
res.send(fa);
//bear.name = req.body.name;
/*
FA.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'FA updated!' });
});
*/
});
})
/*
// delete the bear with this id
.delete(function(req, res) {
FA.remove({
_id: req.params.bear_id
}, function(err, FA) {
if (err)
res.send(err);
res.json({ message: 'Successfully deleted' });
});
});
*/
//REGISTER OUR ROUTES -------------------------------
app.use('/DNZ', router);
//START THE SERVER
//=============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
/*
// set static directories
app.use(express.static('./dist'));
app.use(cors());
// Define Routes
var index = require('./routes/index');
var users = require('./routes/users');
//Set up routes
routes.init(app)
//run
app.listen(port);*/
console.log('Server started, Listening on port ', port);
I used the "template" from the Bear tutorial:
https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4
the problem here is already, that there is no message: "DB connection alive". However, in the bear tutorial (whose code I used here), the DB connection is built and I can insert bear documents in the database. However, here it does not work...
and this is my FA Schema model from FA.js:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var FASchema = new Schema({
Timestamp: Date,
PrognostizierterBetriebswert: Number,
posFlexPot: Number,
negFlexPot: Number,
Leistungsuntergrenze: Number,
Leistungsobergrenze: Number,
posGesEnergie: Number,
negGesEnergie: Number,
Preissignal: Number,
Dummy1: Schema.Types.Mixed,
Dummy2: Schema.Types.Mixed,
Dummy3: Schema.Types.Mixed
//same: Dummy: {}
});
//var FASchema = new Schema({name: String});
module.exports = mongoose.model("FA", FASchema, 'FA');
console.log("FA wird ausgeführt!");
Anybody got an idea why there is no DB connection created?
when I test your code , the Error (Can't set headers after they are sent) was thrown. you can delete res.send(JSON.stringify(req.body)); and restart service

How to use nodejs RESTful api to query from multiple collections?

nodejs noobie here,
I have created nodejs RESTful api for fetching data from three different collections. Here is the article which helped me nodejs api in 10 minutes
After creating APIs, I am able to hit the APIs through postman and get data there. Now I wish to move on to next step of querying records from multiple collections
Server.js
var express = require('express'),
app = express(),
port = process.env.PORT ||3000,
mongoose = require('mongoose'),
menu = require('./app/api/bestseller_books/models/bestsellerBooksModel'),
admin = require('./app/api/admin/models/adminModel'),
test = require('./app/api/test/models/testModel'),
bodyParser = require('body-parser');
var Schema = mongoose.Schema;
var cors = require('cors');
// mongoose instance connection url connection
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/takebook', { useMongoClient: true });
/*mongoose.model('menu', new Schema({ title: String, id: Number }));*/
var menu = mongoose.model('bestseller_books');
var test = mongoose.model('test');
var admin = mongoose.model('admin');
var routes = require('./app/api/bestseller_books/routes/bestsellerBooksRoutes');
var routes2 = require('./app/api/admin/routes/adminRoutes');
var routes3 = require('./app/api/test/routes/testRoutes');
menu.find({}, function(err, data) { console.log(err, data.length); });
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
routes(app); //register the route
/*routes2(app);
routes3(app);*/
app.listen(port);
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
console.log('RESTful API server started on: ' + port);
bestsellerbooks controller
'use strict';
var mongoose = require('mongoose'),
menu = mongoose.model('bestseller_books');
exports.list_all_menus = function(req, res) {
menu.find({}, function(err, menu) {
if (err)
res.send(err);
res.json(menu);
console.log(res);
});
};
exports.create_a_menu = function(req, res) {
var new_menu = new menu(req.body);
new_menu.save(function(err, menu) {
if (err)
res.send(err);
res.json(menu);
});
};
exports.read_a_menu = function(req, res) {
menu.findById(req.params.menuId, function(err, menu) {
if (err)
res.send(err);
res.json(menu);
});
};
exports.update_a_menu = function(req, res) {
menu.findOneAndUpdate({_id: req.params.menuId}, req.body, {new: true}, function(err, menu) {
if (err)
res.send(err);
res.json(menu);
});
};
exports.delete_a_menu = function(req, res) {
menu.remove({
_id: req.params.menuId
}, function(err, menu) {
if (err)
res.send(err);
res.json({ message: 'bestseller_books successfully deleted' });
});
};
My questions are :
Do I have to create new set of models, controllers and routes for
each API?
Looking at the server.js, is this the best practice of
setting up API routes?
What is the use of create_a_menu methods
mentioned in API controllers, if I have to hit API in this format:
app.controller('booklister', ['$http', function($http) {
var self = this;
$http.get('http://localhost:3000/bestseller_books')
.then(function(response)
{
/*$('.fa-refresh').hide();*/
self.items = response.data;
}, function(errResponse) {
/*$('.fa-refresh').show();*/
console.error('Service Error while fetching books' + errResponse);
});
Just create more from everything.
New model, new schema, new Bl layer, new route that take care for that new collection.
For example:
In yore dotsModel.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var DotsSchema = new Schema({
x: {
type: Number
},
y: {
type: Number
}
});
module.exports = mongoose.model('Dots', DotsSchema);
In youre dotsController.js:
var mongoose = require('mongoose'),
Dots = mongoose.model('Dots')
exports.get_all_dots = function (req, res) {
Dots.find({}, function (err, task) {
if (err)
res.send(err);
res.json(task);
});
};
And in your dotsRoutes.js:
module.exports = function(app) {
var todoList = require('../controllers/ dotsController.js:');
app.route('/dots')
.get(todoList.get_all_dots);
Note:
The article you read is short and he touch really briefly on each topic, it's highly recommended to take another course, much longer, and take the time to learn each part of your application, and what node capable of.

Dynamic CRUD functions with Node, Express and Pug

Hi I am new to backend node applications and I am trying to create a clean API driven node.js app without frameworks by working with scripts and pug template engine.
I have created a serve.js file with all the necessary code:
var express = require('express');
var app = express();
var path = require('path');
var favicon = require('serve-favicon');
const bodyParser = require("body-parser");
var mongodb = require("mongodb");
const MongoClient = require('mongodb').MongoClient
var ObjectID = mongodb.ObjectID;
var indexRoutes = require('./routes/index');
var thePort = process.env.PORT || 5000;
var SECTIONS_COLLECTION = "sections";
//make results available as json
app.use(bodyParser.json());
//External database identifier
var db;
//Path to the database with URI
var dbpath = process.env.MONGODB_URI || 'mongodb://heroku_fmvc5nhk:5rqdhjqc2orjhen7knanjpfmd7#ds014586.mlab.com:19986/heroku_fmvc5nhk';
// Connect to the database before starting the application server.
mongodb.MongoClient.connect(dbpath, function (err, database) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
db = database;
console.log("Database connection ready");
//static folder directory
app.use(express.static(__dirname + '/dist'));
// Initialize the app.
var server = app.listen(process.env.PORT || thePort, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
});
// Generic error handler used by all endpoints.
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
res.status(code || 500).json({"error": message});
}
//set up routes directory
app.use('/', indexRoutes);
// Views and Template Engine
//app.set('views', __dirname + './views');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// sections API ROUTES:
/* "/api/sections"
* GET: finds all sections
* POST: creates a new contact
*/
app.get("/api/sections", function(req, res) {
db.collection(SECTIONS_COLLECTION).find({}).toArray(function(err, docs) {
if (err) {
handleError(res, err.message, "Failed to get sections.");
} else {
res.status(200).json(docs);
}
});
});
app.post("/api/sections", function(req, res) {
var newContact = req.body;
if (!req.body.name) {
handleError(res, "Invalid user input", "Must provide a name.", 400);
}
db.collection(sections_COLLECTION).insertOne(newContact, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to create new contact.");
} else {
res.status(201).json(doc.ops[0]);
}
});
});
/* "/api/sections/:id"
* GET: find contact by id
* PUT: update contact by id
* DELETE: deletes contact by id
*/
app.get("/api/sections/:id", function(req, res) {
db.collection(SECTIONS_COLLECTION).findOne({ _id: new ObjectID(req.params.id) }, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to get contact");
} else {
res.status(200).json(doc);
}
});
});
app.put("/api/sections/:id", function(req, res) {
var updateDoc = req.body;
delete updateDoc._id;
db.collection(SECTIONS_COLLECTION).updateOne({_id: new ObjectID(req.params.id)}, updateDoc, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to update contact");
} else {
updateDoc._id = req.params.id;
res.status(200).json(updateDoc);
}
});
});
app.delete("/api/sections/:id", function(req, res) {
db.collection(SECTIONS_COLLECTION).deleteOne({_id: new ObjectID(req.params.id)}, function(err, result) {
if (err) {
handleError(res, err.message, "Failed to delete contact");
} else {
res.status(200).json(req.params.id);
}
});
});
In my views\about.pug template I reference my JSON object's contents.
//--about.pug
extends index.pug
block div.root
h2= #{about.heading}
h3= #{about.summary}
p #{about.content}
In my routesroutes/index.js I have pre-existing "flat" examples with pug then one dynamic about example:
var express = require('express');
var router = express.Router();
router.get('/', function (req, res) {
res.render(
'index',
{
title: 'Welcome to Awesome Place',
header: 'Home',
summary: 'This is my home. It can\'t be any simpler'
}
)
})
Dynamic example:
//About
router.get('/about', function (req, res) {
//retrieve all home from Mongo
db.collection(SECTIONS_COLLECTION).find({"name": "about"}), function (err, about) {
if (err) {
handleError(res, err.message, "Failed to get sections.");
} else {
res.render('about', {})
console.log(result)
}
}
})
The above is returning a db is not defined error.
If var indexRoutes = require('./routes/index'); is required as part of my server.js file, why can't it find the value of db?
UPDATED CODE (TOO MANY ERRORS)
//server.js
//APP Dependences
var express = require('express');
var app = express();
var path = require('path');
var favicon = require('serve-favicon');
var indexRoutes = require('./routes/index');
var bodyParser = require("body-parser");
//PORT
var thePort = process.env.PORT || 5000;
// Views and Template Engine
//app.set('views', __dirname + './views');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
//Documents
app.use(bodyParser.json());
//static folder directory
app.use(express.static(__dirname + '/dist'));
//set up routes directory
app.use('/', indexRoutes);
// Catch errors
app.use(function(req, res, next) {
res.status(404).sendFile(process.cwd() + '/app/views/404.htm');
});
// Initialize the app.
var server = app.listen(process.env.PORT || thePort, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
});
var mongodb = require("mongodb");
const MongoClient = require('mongodb').MongoClient
var ObjectID = mongodb.ObjectID;
var SECTIONS_COLLECTION = "sections";
//External database identifier
var db;
//Path to the database with URI
var dbpath = process.env.MONGODB_URI || 'mongodb://heroku_fmvc5nhk:5rqdhjqc2ovanbfd7knanjpfmd7#ds019986.mlab.com:19986/heroku_fmvc5nhk';
// Connect to the database before starting the application server.
mongodb.MongoClient.connect(dbpath, function (err, database) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
db = database;
console.log("Database connection ready");
// Initialize the app.
var server = app.listen(process.env.PORT || thePort, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
// Generic error handler used by all endpoints.
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
res.status(code || 500).json({"error": message});
}
//db.js
var express = require('express');
var mongodb = require("mongodb");
var MongoClient = require('mongodb').MongoClient
var ObjectID = mongodb.ObjectID;
var assert = require('assert');
//Path to the database with
var dbpath = process.env.MONGODB_URI || 'mongodb://heroku_fmvc5nhk:5rqdhjqc2ovahen7knanjpfmd7#ds019986.mlab.com:19986/heroku_fmvc5nhk';
//Get the section
var SECTIONS_COLLECTION = "sections";
// Use connect method to connect to the server
var database;
function connectMongo(cb){
MongoClient.connect(dbpath , function(err, database) {
assert.equal(null, err);
console.log("Connected successfully to server");
cb(database);
});
}
module.exports = connectMongo;
//routes/index.js
var express = require('express');
var router = express.Router();
var connectDB = require ('../db')
router.get('/', function (req, res) {
res.render(
'index',
{
title: 'Welcome to Awesome Place',
header: 'Home',
summary: 'This is my home. It can\'t be any simpler'
}
)
})
connectMongo(function(database){
//About
router.get('/about', function (req, res) {
//retrieve all home from Mongo
database.collection(SECTIONS_COLLECTION).find({"name": "about"}), function (err, about) {
if (err) {
handleError(res, err.message, "Failed to get sections.");
} else {
res.render('about', {})
console.log(result)
}
}
})
}
router.get('/work', function (req, res) {
res.render(
'work',
{
title: 'Work, Work, Work , Work...',
header: 'Work life',
summary: 'My first work for this bitch',
imgUrl: '/img/firaz.jpg'
}
)
})
router.get('/contact', function (req, res) {
res.render(
'contact',
{
title: 'Contact Me Any Time',
header: 'Contact Me Any Time',
summary: 'Fill the form below to be contacted'
}
)
})
module.exports = router;
Because db variable is not global by requiring var indexRoutes = require('./routes/index'); you are importing the objects from routes/index file to server not the other way around.
what you can do is make your db variable global global.db and access it anywhere or create a seperate file for mongo db connection and require that in routes file
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');
// Connection URL
var url = 'mongodb://localhost:27017/database';
// Use connect method to connect to the server
var database;
function connectMongo(cb){
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected successfully to server");
cb(db);
});
}
module.exports = connectMongo;
This github Repo got good structure for mongoDB
https://github.com/OmarElGabry/chat.io

Resources