ExpressJS require() load order and Mongoose missing ModelSchema - node.js

I'm learning the MEAN stack and have found myself with a load order issue that doesn't seem to make sense.
The below code shows my server.js loading the routes file, which in turn pulls in the controller for a model, which in turn requires the model itself.
If I don't include a reference to the model from routes.js I get a MissingSchemeError when I startup the server. Why? Am I missing something regarding the loading of resources?
My understanding was that the exports for a file would be completely imported by the require() prior to attempting to run any code.
server.js
// modules =================================================
var express = require('express');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var mongoose = require('mongoose');
var morgan = require('morgan');
var app = express();
// configuration ===========================================
// config files
var db = require('./config/db');
// set our port
var port = process.env.PORT || 8080;
// connect to our mongoDB database
mongoose.connect(db.url);
// get all data/stuff of the body (POST) parameters
// parse application/json
app.use(bodyParser.json());
// parse application/vnd.api+json as json
app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// override with the X-HTTP-Method-Override header in the request. simulate DELETE/PUT
app.use(methodOverride('X-HTTP-Method-Override'));
// set the static files location /public/img will be /img for users
app.use(express.static(__dirname + '/public'));
// set morgan to log requests
app.use(morgan('dev'));
// routes ==================================================
require('./app/routes')(app);
routes.js
//this line is the problem. why is this needed?
var Customer = require('./models/customer'); // <--
var customers = require('./controllers/customer-server-controller');
module.exports = function(app) {
app.route('/api/customers')
.get(customers.list);
//.post(customer.create);
}
customer-server-controller.js
var mongoose = require('mongoose');
var Customer = mongoose.model('Customer');
/**
* List of Customers
*/
exports.list = function(req, res) {
Customer.find().sort('-created').exec(function(err, customers) {
if (err) {
return res.status(400).send({
message: "ERROR: " + err
});
} else {
res.jsonp(customers);
}
});
};
Got a good portion of the biolerplate from this tutorial on Scotch.io

I take it that you're missing the model from the tutorial
You should have this somewhere.
Create a models folder and add todo.js and add the following:
// define model =================
var Todo = mongoose.model('Todo', {
text : String
});

Your customer-server-controller.js doesn't require() the model file, it just tries to reference the model by asking Mongoose for it (Mongoose doesn't load the model file for you!):
var Customer = mongoose.model('Customer');
You need to require() the module file from your controller, otherwise the model isn't registered with Mongoose and you get the error that you got.

Related

TypeError: Router.use() requires a middleware function but got a Object[using express router] --

The app, I am building with nodeJS expressJS is for connecting to a sqlserver database and retrieving data. Am trying to make the code as modular and
reusable as posssible. So different files for routing and controller. The error I am now facing is-
throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
^
TypeError: Router.use() requires a middleware function but got a Object
For ease of understanding of the imports, my project structure is as such:
controller
|-- controller.js
db
|-- db.js
query
|-- queries.json
routes
|-- route.js
package.json
server.js
My main server.js file is
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const fs = require('fs')
const path = require('path')
const morgan = require('morgan')
const router=require('./routes/route');
const app = express()
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(morgan('dev'));
const port = 3200
app.listen(process.env.PORT || port , (err) => {
if(err)
{
console.log('Unable to start the server!');
}
else
console.log('NodeExpress Data API started running on : ' + port);
})
the controller file is
const express=require('express')
const { sql, poolPromise } = require('../db/db')
const fs = require('fs');
class MainController
{
async getAllData(req, resp)
{
try
{
const pool = await poolPromise
const result = await pool.request()
.query("select * from players");
resp.json(result.recordset)
}
catch (error)
{
resp.status(500)
resp.send(error.message)
}
}
}
const controller=new MainController();
module.exports=controller;
and the route file is
const express = require('express');
const controller = require('../controller/controller')
const router = express.Router();
router.get('/getAllData', controller.getAllData);
So when I insert this line
app.use('api/', router) in the server.js to wire all the modules together and make calls to api endpoint to get all data, I am getting that error mentioned.
What is it about, can anyone explain me in simple terms? Is the error being thrown from the controller file, since I am initializing a new instance of the controller type? Which line from which file is throwing this error? What is the code correction needed to remove this error?
under route.js change to router.get('/getAllData', controller.getAllData()); you have passed controller.getAllData as a handler function instead of controller.getAllData() as per the type of method you have used in class. hope this solves the error.
Try out one of these:
1- if your are using express and doing
const router = express.Router();
make sure to
module.exports = router ;
at the end of your page
2- If your are using express above 2.x, you have to declare app.router like below code. Please try to replace your code
app.use('/', routes);
with
app.use(app.router);
routes.initialize(app);

node and express error "cannot GET /" even after I included app.get() in my server.js

I am trying to start my project via launching server.js but I am getting error:"cannot GET /"
even after I made an app.get() route in my server.js
I am using also "body-parser" as a middleware, and "cors"
server.js:
// Setup empty JS object to act as endpoint for all routes
const projectData = {};
// Require Express to run server and routes
const express = require('express');
// Start up an instance of app
const app = express();
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
const cors = require('cors');
app.use(cors());
// Initialize the main project folder
app.use(express.static('views'));
const port = 8080;
app.use(express.static('dist'));
// Setup Server
const server=app.listen(port, ()=>{console.log(`running on localhost: ${port}`)});
app.get('/all', sendData);
function sendData (request, response) {
response.send(projectData);
};
// TODO-ROUTES!
app.post('/add', Info);
function Info(req, res) {
projectData['date'] = req.body.date;
projectData['temp'] = req.body.temp;
projectData['content'] = req.body.content;
res.send(projectData);
}
module.exports = server;
I made a POST request to /add and it works. Then I call GET /all and also work. The error cannot GET / is because you are requesting an endpoint that not exists.
Just add a dummy data to your Fn() if you want to see some output on GET request wihtout making any post request
Here is my solution
app.get('/', (req, res) => {
res.redirect('/all');
})
we need this because you do not have any root URL set, so we set the root URL to redirect to /all
2nd step then we add a dummy data in the projectData
var projectData = {
date = new Date().getDate();,
temp = 10,
content="This is Test Content"
}
This way when you call 'http://localhost:8080/' you shall get redirected to http://localhost:8080/all and instead of empty {} you shall see the dummy data.

require is not define / module.exports is not define with node.js and Express

After receveing help about using Express, I continued to follow tutorials about Node.js. I'm at a point where i'm building my own routes in controllers to create a REST API. I have two files, app.js and /controllers/account-api.js.
Here's my app.js shortened (i deleted the parts that were not used my my test), and the line that is returning me some issues.
import express from 'express';
import exphbs from 'express-handlebars';
import * as accountApiRoutes from './controllers/account-controller.js';
import * as bodyParser from 'body-parser';
var app = express();
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
app.use(bodyParser.urlencoded({extended:true}));
app.use(accountApiRoutes); // ISSUE HERE, i tried ('/account-api', accountApiRoutes) too
app.get('/', function(req, res)
{
res.redirect('/server-home');
});
app.get('/server-home', function(req, res)
{
res.render('server-home');
});
app.listen(1337, '127.0.0.1');
console.log('Express Server running at http://127.0.0.1:1337/');
And here's my ./controllers/account-api.js shortened again to give the main elements that causes the issue :
import express from 'express';
const apiRouter = express.Router(); //ISSUE HERE
var accounts = [];
accounts.push( { code: 1, name: 'Pierrette', adress: 'Sur la Lune'} );
// =========== API ROUTES =========== //
// GET
apiRouter.route('/produit-api/produit/:code')
.get( function(req, res, next) {
var codeSended = req.params.code;
var account = findAccountInArrayByCode(codeSended);
res.send(account);
});
// =========== METHODS AND FUNCTIONS =========== //
// GET
function findAllAccounts() {
return accounts;
}
function findAccountInArrayByCode(codeSended) {
var accountFound = null;
for(i in accounts)
{
if(accounts[i].code === codeSended)
{
accountFound = accounts[i];
break;
}
}
return accountFound;
}
module.exports = { //ISSUE HERE
getApiRouter: function() {
const apiRouteur = express.Router();
return apiRouter;
}
}
The problem is.. This code returns me "module" is not defined.
I use Node.JS with Express and Handlebars.
For what I saw online, when using "app.use", it requires a function. And module.exports too. I tried various solutions, like this one :
account-api.js
const apiRouter = function() { return express.Router() }
...
module.exports = apiRouteur;
The problem is that it changes the type of apiRouteur, when calling apiRouteur.get from IRouter to () => Router, and the routes break.
I don't know how to arrange the code to make the module.exports returning a function that works, or if the problem is not even about the type of value returned, but if I'm missing dependancies, etc...
Thanks for your help.
EDIT : With the explanations I got, I replaced all my ES6 calls to commonjs imports. But it doesn't solve the problem. Now it's "require" that's not define.
I was stuck firstly by "require is not defined", and the solution I was given by reading old SO threads about it, the answer was regularly to use ES6 imports...
ack to the begining I guess ! Maybe I miss something in my project?
Your problem is this line app.use(accountApiRoutes); and you are using a mix of ES6 and commonjs modules.
To fix the module imports (as you are using .js files not .mjs) change all your ES6 imports i.e import * as xyz imports to commonjs imports const x = require('...');
The accountApiRoutes is an object but not a Router object.
To fix you just need to pass the router object to the app.use function.
So you will need to make a couple of changes based on what you have supplied above.
// ./controllers/account-api.js
const express = require('express');
...
module.exports = { //ISSUE HERE
getApiRouter: function() {
return apiRouter; // you have already defined the router you don't need to recreate it
}
}
Properly pass the Router object to the express app.
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const accountApiRoutes = require('./controllers/account-controller.js');
...
app.use(accountApiRoutes.getApiRouter());
You could also just set module.exports to your configured router in your account-api.js and then you could pass it directly to app.use as you have already done in your server above. Either way should work. To can do that as follows:
// ./controllers/account-api.js
const express = require('express');
...
module.exports = apiRouter;
And in your server.js
const accountRouter = require('./controllers/account-controller.js');
app.use(accountRouter);

No output from Node app

I am trying to run a simple node application using nide modules and testing it using the Advance Rest Client.
The console is not showing any error.
But I am not getting anything in the output.
While running this on ARC, I am getting : Cannot /GET data
Text version of the code:
MainFile:
var express = require('express');
//var morgan = require('morgan');
var bodyparser = require('body-parser');
var hostname = 'localhost';
var port = '3000';
var app = express();
//app.use(morgan('dev'));
var dishRouter = express.Router();
dishRouter.use(bodyparser.json());
var allDishes = require('./dishRouter');
//For all dishes
dishRouter.route('/dishes')
.get(allDishes.dishesGet)
.delete(allDishes.dishesDelete)
.post(allDishes.dishesPost)
;
//For specific dishesDelete
dishRouter.route('/dishes/:dishid')
.get(allDishes.dishSpecificGet)
.delete(allDishes.dishSpecificDelete)
.put(allDishes.dishSpecificPut)
;
app.listen(port,hostname,function(){
console.log('server runing properly');
});
dishRouter file:
console.log('in dishrouter file');
module.exports.dishesGet = function(req,res,next){
console.log('inside GET');
res.end('Will be displaying all the dishes');
};
module.exports.dishesDelete = function(req,res,next){
res.end('Will delete all the dishes');
};
module.exports.dishesPost = function(req,res,next){
res.end('will add the new dishes');
};
module.exports.dishSpecificGet = function(req,res,next){
res.end('displaying the specific dish :'+req.params.dishid);
};
module.exports.dishSpecificDelete = function(req,res,next){
res.end('Will delete the specific dish with id : '+req.params.dishid);
};
module.exports.dishSpecificPut = function(req,res,next){
res.write('will update the specific dish :'+req.params.dishid);
res.end('Updating the dish with values as name : '+req.body.name);
};
According to body-parser docs
Looks like your router is a bit broken here:
dishRouter.use(bodyParser.json())
Try switching this to:
app.use(bodyParser.json())
And I can recommend creating router in the file, where you write handlers and just export router.
UPDATE:
Here is what you forgot:
app.use(dishRouter)
When calling express.Router() you're just creating an instance of the router, but you have to connect it to the express application instance.

Nodejs Mongoose - Model not defined

I'm trying to send some data to a database using mongoose. Here is my code so far.
server.js
var express = require('express');
var wine = require('./routes/wines');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app = express();
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());
app.get('/wines', wine.findAll);
app.get('/wines/:id', wine.findById);
app.listen(3000);
console.log('Listening on port 3000...');
wine.js (inside models folder)
var mongoose = require('mongoose');
var db = mongoose.connection;
var wineSchema = new mongoose.Schema({
name: String,
description: String
});
var Wine = mongoose.model('Wine', wineSchema);
module.exports = Wine;
wines.js (inside routes folder)
exports.addWine = function(req, res) {
// Problem not defined here
var silence = new Wine({ name: 'Silence', description:"cena" })
console.log(silence.name) // 'Silence'
// add it to the database
};
I keep getting this error and i have no idea why.
ReferenceError: Wine is not defined
I've exported Wine in wine.js (models), shouldn't I be able to use it everywhere ?
Thank you in advance !
Add var Wine = require('./../models/wine.js'); at the beginning of wines.js (assuming your routes and models folders are contained within the same directory).
Exporting objects/values/functions from node modules does not make them globally available in other modules. The exported objects/values/functions are returned from require (reference here for more info). That said, Mongoose uses an internal global cache for models and schemas which make it available via mongoose (or a connection) throughout an app.
So in your routes file you could do something like:
var Wine = mongoose.model('Wine'); // Notice we don't specify a schema
exports.addWine = function(req, res) {
var silence = new Wine({ name: 'Silence', description:"cena" })
console.log(silence.name) // 'Silence'
// add it to the database
};

Resources