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));
});
});
};
....
Related
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.
I have multiple routes setup. I want to get specific data from another route. That data is coming from a post method.
My server.js look like this:
var mysql = require('mysql')
var morgan = require('morgan')
var cors = require('cors')
var bodyParser = require('body-parser')
var http = require('http')
var dateFormat = require('dateformat')
const port = process.env.PORT || 3000;
//middleware
var app = express()
app.use(cors())
app.use(morgan('dev'))
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}))
var now = new Date()
//routes
var user_details = require('./routes/users')
var user_orders = require('./routes/order')
//Use routes
app.use('/', user_details)
app.use('/', user_orders)
//Launch Server
app.listen(port, () => {
console.log('Server start at port: ' + port)
})
My routes/users.js :
var router = express.Router()
var db = require('../dbConfig')
var randomstring = require("randomstring");
var moment = require('moment')
router.post('/list', (req, res) => {
var appendRandomString = randomstring.generate({
length: 10,
capitalization: 'uppercase',
readable: true
})
var id = 'PEPPR_' + appendRandomString
var email = req.body.email
var listItems = req.body.listItems
var listTitle = req.body.listTitle
var date = moment().format("Do MMMM YYYY");
var time = moment().format("LT");
const INSERT_USER_LISTS = `INSERT INTO user_lists (id,date,time,user_email,list_title,list_items) VALUES('${id}','${date}','${time}','${email}','${listTitle}','${listItems}')`
db.query(INSERT_USER_LISTS, (err, success) => {
if (err) {
return res.send(err)
} else {
console.log('list added')
res.send('list added')
}
})
})
module.exports = router
And my routes/order.js
var router = express.Router()
var db = require('../dbConfig')
var randomstring = require("randomstring");
var moment = require('moment')
var user_details = require('./users')
router.post('/sendOrder', (req, res) => {
var email = req.body.email
var status = 'Order Confirmed'
var date = moment().format("Do MMMM YYYY");
var time = moment().format("LT");
var appendRandomString = randomstring.generate({
length: 10,
capitalization: 'uppercase',
readable: true
})
var id = 'PEPPR_ORDER_' + appendRandomString
var list_items = ''
var list_title = ''
var data = {
id: id,
email: email,
list_items: list_items,
list_title: list_title,
date: date,
time: time,
status: status
}
const CREATE_ORDER = `INSERT INTO user_orders SET ?`
db.query(CREATE_ORDER, data, (err, success) => {
if (err) {
return res.send(err)
} else {
res.send('oc')
}
})
})
module.exports = router
I want the list_items and list_title in my order.js from users.js , this two data is coming from a POST method as you can see in users.js
If I understood you correctly you want to use request body which comes to /users in another route /orders.
You are saving user data list_title and list_item in users table. So all you need to access the data from /orders route is make an additional query to db where you will select users by id\email.
Not sure which db ORM you use but in general cases your code may look like this:
router.post('/sendOrder', async (req, res) => {
const { email } = req.body;
// declare other fields
const user = await db.query(
`SELECT * FROM users WHERE email LIKE '%${email}%'`,
(err, success) => {
if (err) {
return res.send(err);
} else {
res.send('ok');
}
}
);
// declare `data` object with user.list_title, user.list_item
const CREATE_ORDER = `INSERT INTO user_orders SET ?`;
db.query(CREATE_ORDER, data, (err, success) => {
if (err) {
return res.send(err);
} else {
res.send('ok');
}
});
});
TypeError: Cannot read property 'then' of undefined
Can you help me fix this? Thank you.
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var mongodb = require('mongodb');
var dbConn = mongodb.MongoClient.connect('mongodb://localhost:27017',
function(err, db) {
if(err){
throw err;
}else{
console.log("connected");
}
})
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.resolve(__dirname, './')));
app.post('/post-feedback', function (req, res) {
dbConn.then(function(db) {
delete req.body._id; // for safety reasons
db.collection('feedbacks').insertOne(req.body);
});
res.send('Data received:\n' + JSON.stringify(req.body));
});
app.get('/view-feedbacks', function(req, res) {
dbConn.then(function(db) {
db.collection('feedbacks').find({}).toArray().then(function(feedbacks) {
res.status(200).json(feedbacks);
});
});
});
app.listen(process.env.PORT || 3000, process.env.IP || '0.0.0.0' );
TypeError: Cannot read property 'then' of undefined
Can you help me fix this? Thank you.
The following approach should get you started but should not use this for production (Reference: How do I manage MongoDB connections in a Node.js web application?). Read through for another production starters.
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var mongodb = require('mongodb');
var dbConn = function() {
return new Promise((resolve, reject) => {
mongodb.MongoClient.connect('mongodb://localhost:27017',
function(err, db) {
if(err){
return reject(err);
}else{
return resolve(db);
}
});
});
}
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.resolve(__dirname, './')));
app.post('/post-feedback', function (req, res) {
dbConn()
.then(function(db) {
delete req.body._id; // for safety reasons
db.collection('feedbacks').insertOne(req.body);
res.send('Data received:\n' + JSON.stringify(req.body));
})
.catch(err => {
console.log(err)
res.send('Error');
})
});
app.get('/view-feedbacks', function(req, res) {
dbConn()
.then(function(db) {
db.collection('feedbacks').find({}).toArray().then(function(feedbacks) {
res.status(200).json(feedbacks);
});
})
.catch(err => {
console.log(err);
res.status(500).json({});
});
});
app.listen(process.env.PORT || 3000, process.env.IP || '0.0.0.0' );
Production Starter:
Ideally you will have something like following say in a file db.js
let mongoClient = require('mongodb').MongoClient,
logger = require('winston');
function DATABASE() {
this.dbObj = null;
this.myCollection = null; // You will need to add more collections here
}
DATABASE.prototype.init = function (config, options) {
let self = this;
self.config = config; //can pass a config for different things like port, ip etc.
self.logger = logger;
return new Promise(function (resolve, reject) {
if (self.initialized) {
return resolve(self);
}
let connectionUri = "mongodb://localhost:27017"; //self.config.mongo.connectionUri;
mongoClient.connect(connectionUri, {native_parser: true}, function (err, db) {
if (err) {
reject(err);
}
else {
self.dbObj = db;
self.myCollection = db.collection('myCollection');
self.initialized = true;
self.logger.info("db init success");
return resolve(self);
}
});
});
};
var dbObj = null;
var getdbObj = function () {
if (!dbObj) {
dbObj = new DATABASE();
}
return dbObj;
}();
module.exports = getdbObj;
In your main app start file you will have something like:
let dbObj = require('./db.js');
dbObj.init()
.then(db => {
console.log('db initialized successfully');
//db.dbObj.collection('myCollection').find()
//or
//db.myCollection.find() because this has been already initialized in db.js
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.resolve(__dirname, './')));
app.post('/post-feedback', function (req, res) {
delete req.body._id; // for safety reasons
db.dbObj.collection('feedbacks').insertOne(req.body);
res.send('Data received:\n' + JSON.stringify(req.body));
});
app.get('/view-feedbacks', function(req, res) {
//db.collection('feedbacks')
});
app.listen(process.env.PORT || 3000, process.env.IP || '0.0.0.0' )
})
.catch(err => console.log(err));
Try this, dbConn is not promise
app.post('/post-feedback', function (req, res) {
mongoose.connection.db.collection('feedbacks', function (err, collection) {
collection.insertOne(req.body);
res.send('Data received:\n' + JSON.stringify(req.body));
});
// OR
const Model = mongoose.model('feedbacks');
let model = new Model();
model = Object.assign(model, req.body);
model.save().then((result) => {
res.send('Data received:\n' + JSON.stringify(req.body));
});
});
Its working .
If you are getting any TypeError (UnhandledPromiseRejectionWarning: TypeError: db.collection is not a function) form mongodb. Just change the version of mongodb to -
"mongodb": "^2.2.33"
"use strict"
var express = require('express');
var mongodb = require('mongodb');
var app = express();
var MongoClient = mongodb.MongoClient;
var url = 'mongodb://localhost:27017/feedback';
// no need to call then() yet
var dbConn = MongoClient.connect(url);
app.set('port', 5000);
app.listen(app.get('port'), function() {
console.log('feedback is running on port', app.get('port'));
});
app.get('/view-feedback', function(req, res, next) {
// the connection is opened
dbConn.then(function(db) {
// var dbo = db.db("feedback");
db.collection('feedback').find({}).toArray().then(function(docs) {
// return docs;
res.json(docs)
});
});
});
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.
I'm prety new to nodejs and even more so Sequelize. I'm trying to setup an API to MSSQL using Sequelize but some of the basics are eluding me. I just can't seem to interact with my SQL DB.
This is my server.js file
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var models = require('./models');
var port = process.env.PORT || 3011;
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
var transactionRouter = require('./server/Routes/transactionRoutes')();
var userRouter = require('./server/Routes/userRoutes')();
var authRouter = require('./server/Routes/authRoutes')();
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8012');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', false);
// Pass to next layer of middleware
next();
});
app.use('/api/transactions', transactionRouter);
app.use('/api/auth', authRouter);
app.use('/api/users', userRouter);
app.get('/', function(req, res) {
res.send('welcome to my API');
});
app.listen(port, function() {
console.log('Gulp is running my app on PORT: ' + port);
});
module.exports = app;
Models/Index.js
var fs = require("fs");
var path = require("path");
var Sequelize = require("sequelize");
var env = process.env.NODE_ENV || "development";
var sequelize = new Sequelize('dbname', 'dbusername', 'dbpassword', {
host: 'dbhostname',
dialect: 'mssql',
pool: {
max: 5,
min: 0,
idle: 10000
}
});
var db = {};
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
})
.forEach(function(file) {
var model = sequelize["import"](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
A model Models/user.js
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('BO_Users', {
username : DataTypes.STRING,
password : DataTypes.STRING,
});
return User;
};
A the routes server/Routes/userRoutes.js
var express = require('express');
var models = require('../../models');
var routes = function() {
var userRouter = express.Router();
userRouter.route('/')
.get(function(req, res) {
console.log("Made it to the new route");
console.log("made it to the new get route");
models.User.findAll({})
.then(function() {
console.log('Got some users');
});
})
.post(function(req, res) {
console.log("Made it to the post route");
});
return userRouter;
};
module.exports = routes;
I'm pretty sure I need to do a models.sequelize.sync() somewhere, but I'm kinda lost and having trouble finding a good tutorial that gets through to me. I have the tables in place, I just want to start interacting with them. Thanks!!
As a quick fix, I would suggest putting the .sync() in server.js just prior to and wrapping the listener so that the app cannot be interacted with before the DB is ready.
For example:
models.sequelize.sync().then(function() {
console.log('starting listener on PORT: '+port);
app.listen(port, function(err) {
if(err) return console.error('Failed to start listener: '+err);
console.log('Gulp is running my app on PORT: ' + port);
});
}).catch(function(err) {
console.error('failed to sync DB: '+err);
});