Node/Express - Route/Function conundrum - circular reference - node.js

Smarter programmers, please advise:
two variables coming in from an AJAX post (username, pic)
get them at the route users.js from req.body
have my functions in a file main.Funcs exported to server.js
I can't figure out how to get the variables out of my route and into my server.js, so that I can use them with my functions. Can't figure out how to do it without circular 'require' between routes and mainFuncs.
QUESTIONS:
How do you access variables from routes without (1) making global variables, nor (2) circular require between routes and mainFuncs?
Could set global variables but bad? Some way to call them in a big function that gives access to scope without making global?
server.js
var express = require('express');
var mainFuncs = require('./mainFunctions.js');
mainFuncs.startServer();
mainFuncs.sqlConnectionCheck();
mainFuncs.learnFace(username, picLink);
mainFuncs.js
const client = some api methods, input from route --> api --> json back
var express = require('express');
var users = require('./routes/users');
var bodyParser = require('body-parser');
app.use('/users', users);
var app = express();
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(express.static('public'));
app.use('/', main);
app.use('/users', users);
app.use('/profile', profile);
var mainFuncs = {
startServer: function () {
app.listen(3000, function() {
models.users.sync({ force: true });
models.userPicData.sync({ force: true });
console.log('Listening on port 3000!');
});
},
sqlConnectionCheck: function (){
sequelize
.authenticate()
.then(function(err) {
console.log('Connection to mysql: success.');
})
.catch(function (err) {
console.log('Connection to mysql: failed with these errors: ', err);
});
},
learnFace: function (username, picPath) {
client.faces.detect({ urls: picPath, attributes: 'all' })
.then(function(result){
var newLearn = JSON.parse(result);
var newTid = newLearn.photos[0].tags[0].tid;
var fullNameSpace = username + '#notARealNameSpace';
console.log('You have been registered with the name: ' + username);
client.tags.save(newTid, fullNameSpace, {label: nameString, password: 'optionalPassword'});
client.faces.train(nameString, { namespace: 'urface' });
})
},
};
module.exports = mainFuncs;
routes/users.js
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
var app = express();
router.post('/create', function(req,res){
var username = req.body.username;
var picLink = req.body.pic;
});
module.exports = router;

Typically express apps are structured so that the Business Logic, Routes and Express server are in separate locations. The actual logic to your app goes inside a directory /lib. Your routes go inside /routes and your server.js goes into your project root.
/<root>
/lib
/public
/routes
server.js
package.json
Do you mean my mainFuncs should be imported into the router? It just seems like I'm writing most of the program in the routes at that point?
No, your logic goes into separate files inside /lib and your /routes will require it when necessary. This approach is decoupled and allows your logic to live outside of your routes. The logic may be implemented in multiple routes if necessary yet be centralized and easy to maintain. This leaves your routes free to only implement the code needed to determine the response and update session state.
The above code could be structured as so:
server.js
const express = require('express');
const bodyParser = require('body-parser');
const users = require('./routes/users');
// Place DB and any other initialization here in server.js
// so it will be guaranteed to execute prior to the server listening
const app = express();
const port = process.env.PORT || 1337;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static('public'));
app.use('/users', users);
app.listen(port, () => {
console.log(`Listening on ${port}`);
});
module.exports = app;
/lib/learnFace.js
const client = require('<package>'); // Some package etc per your question
function learnFace(username, picPath) {
return client.faces.detect({ urls: picPath, attributes: 'all' })
.then(function(result){
let newLearn = JSON.parse(result);
let newTid = newLearn.photos[0].tags[0].tid;
let fullNameSpace = username + '#notARealNameSpace';
console.log('You have been registered with the name: ' + username);
client.tags.save(newTid, fullNameSpace, {label: nameString, password: 'optionalPassword'});
client.faces.train(nameString, { namespace: 'urface' });
});
}
module.exports = learnFace;
/routes/users.js
const router = require('express').Router();
const learnFace = require('../lib/learnFace');
router.post('/create', (req, res) => {
let username = req.body.username;
let picLink = req.body.pic;
return learnFace(username, picLink)
.then(() => {
return res.sendStatus(201);
})
.catch((err) => {
return res.sendStatus(500);
})
});
module.exports = router;
Also you don't need to require Express in every file like you are no need to, only require the things you need in files that you are using.

Related

node, express, mongoose don't work together

Hej people
I try to create some fullstack app (base on one tutorial) and I have some problem with understand how backed part work. Teoreticlly, then I did this tutorial first time, everything was working. But now, then I try to something new base on it, I see how many things I don't understand. Basically, why it won't work.
I generate express app. My app.js looks that:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mongoose = require('mongoose');
var cors = require('cors');
mongoose.connect('mongodb://localhost/covid', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
}).then(() => console.log('connection successful'))
.catch((err) => console.error(err));
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var casesRouter = require('./routes/cases');
var app = express();
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/api', casesRouter);
module.exports = app;
routers/cases.js:
var express = require('express');
var router = express.Router();
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Cases = require('../models/Cases.js');
server.listen(4000)
// socket io
io.on('connection', function (socket) {
socket.on('newdata', function (data) {
io.emit('new-data', { data: data });
});
socket.on('updatedata', function (data) {
io.emit('update-data', { data: data });
});
});
// list data
router.get('/', function(req, res) {
Cases.find(function (err, cases) {
if (err) return next(err);
res.json(cases);
});
})
module.exports = router;
and schema:
var mongoose = require('mongoose');
var CasesSchema = new mongoose.Schema({
id: String,
name: String,
location: String,
state: String,
});
module.exports = mongoose.model('Cases', CasesSchema);
ok, it's all.
So now I run it from my console by nodemon. In console everything looks ok. No error, and message that everything is ok. But app is not working:
1) I expect that this part:
mongoose.connect('mongodb://localhost/covid', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
}).then(() => console.log('connection successful'))
.catch((err) => console.error(err));
should created me now new schema "covid" with object Cases with keys id, name, location, state. It didn't happen. I installed Compass to easiest examination my mongodb and I can see, that I don't have something like covid. ok, I created it manually, But, as I understand, it should be done automaticlly after I run nodemon.
2) I expect that I can examination my backend via postman. https://localhost:3000/api/ (3000 - nodemon default port), but I
Could not get any response There was an error connecting to
https://localhost:3000/api/.
and it's everything. I can't see this error neither in console nor postman.
Maybe I don't understand something with ports in express app, or I don't understand something with mongoDB. But google didn't help me. It did only bigger mess in my head. So maybe someone of you can explain me how it should work and why?

req.body is empty on POST with data, however logging req shows req.body exists

My problem
I am trying to write a register/login page in node.js using express.js. I have decided to split routes and app initialization into two files. When I send a POST request to localhost:3000/register with the data {"username":"xyz","password":"xyz"}, the request object has the attribute body. However when I try to access this attribute, I get undefined.
My current code
// app.js
// Load express and define port
const express = require('express');
const app = express();
const port = 3000;
// App Configurations
app.use(express.json())
// Load Routes
var registerRouter = require('./controllers/register.js');
// Use Routes
app.use('/register', registerRouter);
// Start App
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
// controllers/register.js
// requires
var argon2i = require('argon2-ffi').argon2i;
var bodyParser = require('body-parser');
var {Database, Model} = require('mongorito');
var crypto = require('crypto')
var Promise = require('bluebird');
var randomBytes = Promise.promisify(crypto.randomBytes);
var express = require('express');
// define router
var router = express.Router();
// Mongo Connection
const db = new Database('localhost/test', {
reconnectTries: 5
});
// Models
class User extends Model {}
// Register Models
db.register(User);
// Routes
router.post('/', async (res, req) => {
console.log(req.body);
if(!req.body) return req.sendStatus(400);
const username = req.body.username;
const salt = randomBytes(32);
const password = argon2i.hash(req.body.password, salt);
var user = new User({
username: username,
password: password,
salt: salt
});
await user.save;
res.send("User Created");
});
// Disconnect From Database
db.disconnect;
//export router
module.exports = router;
My expected result
I expect to be able to access req.body and req.body.username.
You have a small issue in you code. The router.post callback function first parameter is req and the second is res. The Callback function parameters are fixed not named parameters.
You are trying to get the body on the response object, though the name of the parameter is req but it still holds the response object. which is causing the issue.
Please change it.
Wrong:
router.post('/', async (res, req) => {
Correct:
router.post('/', async (req, res) => {
I see you are importing bodyParser in controller/register but not setting it, at least in this snippet. if you do not have any special reasons for putting it in the controller, then do this instead.
// app.js
// Load express and define port
const express = require('express');
const bodyParser = require('body-parser'); // new code
const app = express();
app.use(bodyParser.urlencoded({ extended: true })); // new code
const port = 3000;
// App Configurations
app.use(express.json())
// Load Routes
var registerRouter = require('./controllers/register.js');
// Use Routes
app.use('/register', registerRouter);
// Start App
app.listen(port, () => console.log(`Example app listening on port ${port}!`));

How to export models in the form of middle ware in main server.js and write routes for tables in separate model.js file

I am a newbie in node.I have created a server file to connect mongoDB and wrote routes in the same. Created a model.js for table attributes.I want to write a route for my other tables.
https://codingthesmartway.com/the-mern-stack-tutorial-building-a-react-crud-application-from-start-to-finish-part-2/
Taken reference from here. But want to create a seperate file for connection and add module for tables
This is my server.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const todoRoutes = express.Router();
const PORT = 4000;
let Todo = require('./todo.model');
app.use(cors());
app.use(bodyParser.json());
app.use('/todos', todoRoutes);
mongoose.connect('mongodb://127.0.0.1:27017/todos', {
useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established
successfully");
})
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
todoRoutes.route('/').get(function(req, res) {
Todo.find(function(err, todos) {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
this routes are in this file i want to export it from other model.js
If you want to put route in another file,i would suggest you to make a new folder route and then inside it make a new file by route name(say createUser.js).
In this server.js file only use
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const PORT = 4000;
let Todo = require('./todo.model');
app.use(cors());
app.use(bodyParser.json());
app.use('/todos', todoRoutes);
mongoose.connect('mongodb://127.0.0.1:27017/todos', {
useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established
successfully");
})
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
export default app;
And in another file inside route folder use the require imports and define the route here.
const todoRoutes = express.Router();
todoRoutes.route('/').get(function(req, res) {
Todo.find(function(err, todos) {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
module.exports=todoRoute;
Furthur you can import this route in any model.js and use it for implementation of logic.
Note-: You can also use a third folder controllers and implement the route logic there since it is the best practice to not write logic on route but use controller file for it.Also you can separate the DB connection login in another file.

Request body undefined in supertest

I am testing an express API with supertest. I am trying to pass in body parameters into the test, as can be seen in the code snippets below, but it appears that the body parameters don't get passed in correctly since I get an error message that the body parameters are undefined.
Running the test with command mocha --recursive returns the following error:
Cannot read property 'email' of undefined
Below is the code from file email-suite.js referencing supertest
'use strict';
var express = require("express");
var bodyParser = require('body-parser');
var mongoose = require("mongoose");
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
var supertest = require("supertest");
var chai = require("chai");
var should = chai.should();
var api = require("../server.js");
describe("Email Module", function() {
this.timeout(25000);
before(function(done){
mongoose.createConnection(/* connectionstring */);
mongoose.connection.on('open', function(err) {
if(err) console.log(err);
console.log('connected to server');
});
done();
});
it("Check Email Count", function(done) {
var body = { email: "email#email.com" };
supertest(api)
.post("/emailCount")
.set('Accept', 'application/json')
.send(body) // body is undefined
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if(err) return done(err);
res.body.count.should.equal(2);
done();
});
});
});
Below is the code from file email-api.js
'use strict';
var express = require("express");
var bodyParser = require('body-parser');
var router = express.Router();
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
router.post('/emailCount', function(req, res) {
var email = req.body.email; // req.body is undefined
}
module.exports = router;
Below is the code from the file server.js
var express = require("express");
var app = express();
app.set("port", process.env.PORT || 3000);
var router = require("./user/email-api");
app.use('/', router);
app.listen(app.get("port"), function() {
console.log("App started on port " + app.get("port"));
});
module.exports = app;
Put body-parser always after express object and before every routes in main server file like this
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
//Router task start from here
Other wise always will get undefined since router call first and body parsed later.
Thank you abdulbarik for your answer. I want to add some extra information to aid clarity in case people are still getting undefined values for the request body object, and if (as in my case) your routers and tests are setup differently.
Here is the router that we shall test:
// router.js
const express = require("express");
const router = express.Router();
router.post("/", (req, res) => {
res.json({ success: true, data: req.body });
});
module.exports = router;
The following test code will result in the request body being undefined, and thus the test failing:
// router.test.js
const express = require("express");
const request = require("supertest");
const bodyParser = require("body-parser");
// set up the test app - this will fail
const app = express();
app.use("/routerPath", require("./router")); // this will cause the test to fail, as the router should be setup after the body-paser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// run the test
it("successful response", async () => {
const response = await request(app)
.post("/routerPath")
.send({
firstname: "John",
lastname: "Smith",
})
.set("Accept", "application/json");
expect(response.status).toEqual(200);
expect(response.body).toEqual({
success: true,
data: {
firstname: "John",
lastname: "Smith",
},
});
});
The reason why, as explained by abdulbarik, is that the body-parser code should always be before the router code, so that the parser runs before the router. To make the test pass, simply swap these lines around:
// set up the test app - this will work now
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use("/routerPath", require("./router")); // the router setup should happen after the body-parse setup
I hope that is a helpful clarification.

NodeJS module.exports does not work as expected

I am writing a web service in NodeJS using Express. My problem occurs when I want to use the app (Express instance) in other modules. The following configuration works just fine, but if I replace
var app = module.exports = express();
with
var app = express();
and then use
module.exports = app;
at the bottom of app.js, everything will break down. There will be an error when calling app.get() in the auth module (TypeError: app.get is not a function). Can somebody explain to me why it matters where I export the app object?
app.js
var mongoose = require('mongoose');
var express = require('express');
var bodyParser = require('body-parser');
var debug = require('debug')('app');
var morgan = require('morgan');
var config = require('./config');
var app = module.exports = express();
// --- globals ---
app.set('jwtTokenSecret', config.jwtTokenSecret);
// --- middleware ---
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(morgan('dev'));
// --- routes ---
var courses = require('./routes/courses');
var users = require('./routes/users');
var auth = require('./routes/auth');
app.use('/auth', auth);
app.use('/courses', courses);
app.use('/users', users);
// --- database connection ---
mongoose.set('debug', true);
mongoose.connect(config.database, function(err) {
if (err) {
debug('Could not establish connection to mongodb');
} else {
debug('Successfully connected to mongodb');
}
});
routes/auth.js
var express = require('express');
var router = express.Router();
var moment = require('moment');
var jwt = require('jwt-simple');
var User = require("../models/User");
var debug = require('debug')('app');
var app = require("../app");
// POST /auth
router.post('/', function(req, res, next) {
User.findOne({
'username' : req.body.username
}, function(err, user) {
if (err || !user) {
res.status(401).json({ error: "No user found"});
return;
}
if (user.password != req.body.password) {
res.send(401);
}
debug(app.get('database'));
var expires = moment().add(7, 'days').valueOf();
var token = jwt.encode({
user: user.username,
exp: expires
}, app.get('jwtTokenSecret'));
res.json({
success: true,
token: token
});
});
});
module.exports = router;
It's because you have a circular dependency between app.js and auth.js.
In your app.js file, you are requiring auth.js, and inside auth.js, you are requiring app.js. By moving module.exports = app to the bottom of app.js, it is being called AFTER var auth = require('./routes/auth');. This means that when var app = require("../app"); is called inside auth.js, module.exports will not be yet defined inside app.js, hence leading to the error.

Resources