Cannot read property of undefined MVC model web service with mongodb - javascript

Decided to learn some web service development and rain into a problem. I cant seem to find a way how to use ExpressJS Router() to pass POST data to the controller files that i have. When i read contents of the request that was rerouted from product.route.js to the product.controllerjs i get
TypeError: Cannot read property 'name' of undefined
File structure as follows:
nodeTutorial/
app.js
controllers/
product.controller.js
models/
product.model.js
routes/
product.route.js
Node.js Dependencies
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.4",
"mongoose": "^5.4.1"
}
After hours of debugging i was able to get the request data without using any of the Express routing and just simply retrieve the data within the app.js by doing
app.post('/hello', function(req, res){
console.log("name: " + req.body.name + "; price: " + req.body.price);
res.json({requestBody: req.body})
});
This is good, but i would like to stay a little more organized and not put everything into a single file.
app.js code
//app.js
const express = require('express');
const bodyParser = require('body-parser');
const product = require('./routes/product.route'); // Imports routes for the products
const app = express();
// Set up mongoose connection
//........
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/products', product);
//Method that worked for me here (explained above)
let port = 1234;
app.listen(port, () => {
console.log('Server is up and running on port number ' + port);
});
product.route.js
const express = require('express');
const router = express.Router();
const product_controller =
require('../controllers/product.controller');
router.post('/create', product_controller.product_create);
module.exports = router;
product.controller.js
const Product = require('../models/product.model');
//Below is where i need to retrieve data from req
//As of now it prints 'req: undefined'
//And TypeError: Cannot read property 'name' of undefined
exports.product_create = function (req, res) {
console.log("req: "+ req.params.name);//doesnt work
//Also tried all of the below and all return undefied or an Empty Object
console.log("req.params.name: "+req.params.name);
console.log("req.params: "+ req.params);
console.log("req: "+ req.param("name"));
console.log("req.query.name: "+ req.query.name);
console.log("req.query: "+ req.query);
console.log("req.body.name: "+ req.body.name);
console.log("req.body: "+ req.body);
console.log("TEST");
let product = new Product(
{
name: req.body.name,
price: req.body.price
}
};
product.model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let ProductSchema = new Schema({
name: {type: String, required: true, max: 100},
price: {type: Number, required: true},
});
module.exports = mongoose.model('Product', ProductSchema);
When following post request is sent with name and price as body parameters i need to print them out and assign to Product Object
POST /products/create HTTP/1.1
Host: localhost:1234
Content-Type: application/x-www-form-urlencoded
cache-control: no-cache
name=apple%2Cprice=15
Sorry in advance if this is a simple solution, i am new to this whole web service thing.

So you want to handle product related routes in product.controller.
In your app.js, app.use('/products',product.controller)
In product.controller,
const express=require('express')
const router=express.Router()
router.get('/create',(req,res)=>{//your code})

Related

Failed to connect to localhost 5000

I am trying to connect my node app with MongoDB. The code seems to execute as I get the output
Server is running on port 5000
MongoDB database connection established successfully
on the terminal
But when I try to post get from insomnia it takes about two minutes before I get the error
Error: Server returned nothing (no headers, no data)
const express = require('express');
//const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 5000;
app.use(cors());
app.use(express.json());
const uri = process.env.ATLAS_URI;
mongoose.connect( uri, {useUnifiedTopology: true, useNewUrlParser: true}, () => { console.log("MongoDB database conection established successfully")}).catch(err => console.log(err));
const exercisesRouter = require('./routes/exercises');
const usersRouter = require('./routes/users');
app.use('/exercises', exercisesRouter);
app.use('/users', usersRouter);
//emitter.setMaxListeners();
app.listen(port, () => {
console.log('Server is running on port : ' + port);
});
I am following a tutorial and these are the other files I have
exercise.model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const exerciseSchema = new Schema({
username: {type: String,required: true},
description: {type: String,required: true},
duration: {type: Number,required: true},
date: {type: Date,required: true},
},
{
timestamps: true,
});
const Exercise = mongoose.model('Exercise', exerciseSchema);
module.exports = Exercise;
exercises.js
const router = require('express').Router();
let Exercise = require('../models/exercise.model');
router.route('/').get((req, res) => {
Exercise.find()
.then(exercises => res.json(exercises))
.catch(err => res.status(400).json('Error: ' + err));
});
router.route('/add').post((req, res) => {
const username = req.body.username;
const description = req.body.description;
const duration = Number(req.body.duration);
const date = Date.parse(req.body.date);
const newExercise = new Exercise({
username,
description,
duration,
date,
});
newExercise.save()
.then(() => res.json('Exercise added!'))
.catch(err => res.status(400).json('Error: ' + err));
});
module.exports = router;
users.js
const router = require('express').Router();
let User = require('../models/user.model');
router.route('/').get((req,res) => {
User.find()
.then(users => res.json(users))
.catch(err => res.status(400).json('Error: ' + err));
});
router.route('/add').post((req,res) => {
const username = req.body.username;
const newUser = new User({username});
newUser.save()
.then(() => res.join('User added!'))
.catch(err => res.status(400).json('Error: ' + err));
})
module.exports = router;
user.model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
trim: true,
minlenght: 3
},
},{
timestamps: true,
});
const User = mongoose.model('User', userSchema);
module.exports = User;
I also get Cannot GET / when I go to http://localhost:5000 on my browser and in the inspector errors it says Refused to load the image 'http://localhost:5000/favicon.ico' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback. This may be a lot but I am trying to learn how to connect backend with front end and would appreciate it if someone can guide me. Thank you in advanced.
The problem seems to be CORS related. This means that the express API you have created, will not accept calls from other domains and expects the interaction to come from the same application. As you are are using insomnia, which is a separate desktop app or something, express will block access to routes. This is the default behavior.
You need to grab the CORS middleware and set up your routes as needed. Just follow the docs.
A quick test to allow all access:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/users', (req, res) => {...
...
Ther is an other method to add CORS
app.use(function (req, res, next) {
//Enabling CORS
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type,
Accept, x-client-key, x-client-token, x-client-secret, Authorization");
next();
});
I'm also going through the same tutorial: https://www.youtube.com/watch?v=7CqJlxBYj-M
The problem is with app.use(express.json());
Comment that out and it'll work fine. But then you won't be able to parse JSON data when you're doing post requests. I'm not sure why express.json() doesn't work.
But either way you can use Body-Parser to solve that problem. First user npm i body-parser to install it to your package manager in your backend folder. Then copy the below code to your index.js
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
add this code and you'll be fine. This answer gives a detailed explanation of express.json & body-parser.
express.json() is a method inbuilt in express to recognize the incoming Request Object as a JSON Object.
I recommend using body-parser (it is an NPM package) to do the same thing. It is developed by the same peeps who built express and is designed to work with express. body-parser used to be part of express.

Node JS | TypeError: Cannot read property 'first_name' of undefined

Im just starting out with MEAN application, and im stuck while adding data into the database. So please help me to find the solution for this.
This is the root file, entry point in the application
//Importing modules
var express=require('express');
var mongoose=require('mongoose');
var bodyparser=require('body-parser');
var cors=require('cors');
var path=require('path');
var app=express();
const route=require('./routes/route');
//Connect to mongoDb
mongoose.connect('mongodb://localhost:27017/contactlist');
//on connection
mongoose.connection.on('connected',()=>{
console.log("Successfully established a connection to mongodb Database ")
});
//on error
mongoose.connection.on('error',(err)=>{
if(err){
console.log("Failed to established a connection "+err);
}
});
const port=3000;
//For routing
app.use('/api',route);
//Adding middleware -cors
app.use(cors());
//body-parser
app.use(bodyparser.json());
//Static Files
app.use(express.static(path.join(__dirname,'public')));
//port no
app.get('/',(req,res)=>{
res.send('Foobar');
});
app.listen(port,()=>{
console.log("Server started listening to port "+port);
})
And this my route file,
const express = require('express');
const router = express.Router();
// fetching the schema
const Contact = require('../Models/contacts');
//Retriving the contacts
router.get('/contacts', (req,res,next)=>{
Contact.find(function(err,contacts){
// Sending to client in json format
res.json(contacts);
});
});
// Adding Contacts
router.post('/contact', (req,res,next)=>{
let newContact = new Contact({
first_name : req.body.first_name,
last_name : req.body.last_name,
phone : req.body.phone
});
newContact.save((err,contact)=>{
if(err){
res.json({msg: "Failed to add contact."});
}else{
res.json({msg:"Contact added sucessfully"});
}
});
});
//Deleteing contact
router.delete('/contact/id',(req,res,next)=>{
Contact.remove({_id:req.params.id},function(err,result){
if(err){
res.json(err);
}else{
res.json(result);
}
})
});
module.exports=router;
Now, I'm trying to add a few records in DB (Mongo DB) using postman, but it's throwing an error saying "TypeError: Cannot read property 'first_name' of undefined, at router.post (C:\Mean App\ContactList\routes\route.js:16:25)"
In postman, for header, I'm using "Content-type: application/json" and in raw body, I'm adding JSON data like this,
{
"first_name" : "Siddhesh",
"last_name" : "Mishra",
"phone" : "9594106324"
}
And here is my code where I'm creating schema
const mongoose=require('mongoose');
const ContactSchema = mongoose.Schema({
first_name:{
type:String,
required:true
},
last_name:{
type:String,
required:true
},
phone:{
type:String,
required:true
}
});
const Contact=module.exports=mongoose.model('Contact',ContactSchema);
thank you.
You will have to move body-parser above the routes use and should work
//body-parser
app.use(bodyparser.json());
//For routing
app.use('/api',route);
From Express API v4.x
app.use([path,] callback [, callback...])
...
Middleware functions are executed sequentially, therefore the order of
middleware inclusion is important.
body-parser needs to go before the routes:
//Importing modules
var express = require('express');
var mongoose = require('mongoose');
var bodyparser = require('body-parser');
var cors = require('cors');
var path = require('path');
var app = express();
const route = require('./routes/route');
//Connect to mongoDb
mongoose.connect('mongodb://localhost:27017/contactlist');
//on connection
mongoose.connection.on('connected', () => {
console.log("Successfully established a connection to mongodb Database ")
});
//on error
mongoose.connection.on('error', (err) => {
if (err) {
console.log("Failed to established a connection " + err);
}
});
const port = 3000;
//body-parser
app.use(bodyparser.json()); // here
//Adding middleware -cors
app.use(cors());
//Static Files
app.use(express.static(path.join(__dirname, 'public')));
// For routing
app.use('/api', route);
app.get('/', (req, res) => {
res.send('Foobar');
});
app.listen(port, () => {
console.log("Server started listening to port " + port);
})
To always be on the safe side your routes should always come last after all middleware.

JS Fetch posts only object ID to localhost

When I send form data using fetch, only the _id is registered in my database.
Using postman to post does send the correct data to the database. Also, the fetch posts to another server on heroku fine (I don't know how that server has been set up unfortunately).
With postman I've tried setting the Header content type to x-www-form-urlencoded, when that didn't solve the problem, I set the content type to json. That also did not work. The body Content-Type is set to x-www-form-urlencoded.
Using fetch to get the data from the express server (which has cors enabled) works fine. The data is also being correctly logged, so I'm pretty sure it's something with the post request....
sendToServer () {
console.log(this.state)
fetch(`http://localhost:3000`, {
method: "post",
headers: {
// also tried with 'application/json'
'Accept': 'application/x-www-form-urlencoded',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: JSON.stringify(this.state)
})
}
Maybe this adds more clarity, the object I'm expecting is
{
"_id": "59adb44602416d102c095260",
"title":"meetup",
"date":"2017-09-06T00:00:00.000Z",
"venue":"starbucks"
}
But instead I'm getting:
{
"_id": "59adb44c02416d102c095261"
}
The server code:
//index.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
const db = require('./db');
const router = require('./router');
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(router);
app.listen(3000, ()=>{
console.log('express app listening on port 3000')
})
//router.js
const express = require('express');
const router = express.Router();
const controller = require('./controller')
router.get('/', controller.getAll)
router.post('/', controller.create)
module.exports = router;
//controller.js
const mongoose = require('mongoose');
const EventModel = require('./model');
const getAll = async (req, res) => {
res.send(await EventModel.find());
}
const create = async (req, res) => {
const newEvent = EventModel({
title: req.body.title,
date: req.body.date,
venue: req.body.venue,
});
await newEvent.save();
res.send(newEvent);
}
module.exports = {getAll, create};
//model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Event = new Schema({
title: String,
date: Date,
venue: String,
}, {versionKey: false});
const EventModel = mongoose.model('Event', Event);
module.exports = EventModel;
//db.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/cw-events', {useMongoClient: true});
mongoose.Promise = global.Promise;
mongoose.connection.on('connected', () => {
console.log('Mongoose connected')
})
I realised that my problem was that I'd formatted the body-parser to parse requests from postman which were url-encoded. All I had to do was change it to json, so:
//from this
app.use(bodyParser.urlencoded({ extended: false }));
//to this
app.use(bodyParser.json());
So now it parses json format, which is what the fetch is posting.

how to save json object from third party api

I'm having trouble figuring out how to save a json object from a third party api to my personal localhost mongodb. I believe I'm supposed to create another method within the api controller but am not sure what kind of method should be used any help would be great thanks!
Here is my code sorry if this is a dumb question.
//server.js
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var mongoose = require('mongoose');
var Router = require('./routes');
var morgan = require('morgan');
var port = process.env.PORT || 3000;
var app = express();
//database connect
mongoose.connect('mongodb://localhost/Emagispace')
app.use(
express.static('views'),
bodyParser.json(),
bodyParser.urlencoded({extended : true}),
morgan('dev')
);
Router(app);
app.listen(port, ()=>{
console.log(`Server running on ${port}`);
//Routes
var API = require('./controllers/api');
module.exports = (app)=>{
app.get('/', (req, res)=>{
res.sendFile('index.html', {root : './views'});
});
app.get('/api/emagispace', API.product)
}
//API controller
var request = require('request-promise');
var baseURI = 'example';
module.exports = {
product : (req, res)=>{
request({
method : 'GET',
url : `${baseURI}/api/emagispace/${req.query.products}`
})
.then((resp)=>{
console.log('Product list : ', resp);
res.send(resp).save();
})
}
}
In order use mongoose for saving the documents you'll need to specify the Schema first.
//product-model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProductSchema = new Schema({
name: String,
price: String,
//And all other data you need
});
var Product = mongoose.model('Product', ProductSchema);
Also you can do validation and much else. Please see the docs.
Then you can use .insertMany to save them in one shot or iterrate over your documents:
var Product = require('../models/product-model.js');
...
.then((resp)=>{
//I assume that resp is an array of products here
console.log('Product list : ', resp);
//Go over your product list and save them
for (var product of resp) {
var p = new Product(product);
p.save();
}
//OR
Product.insertMany(resp);
res.send(resp);
})
After this you'll have products collection in your local db.
Also you can warp these calls into a method if you want.

Express.js : Cannot POST /users error

I'm trying to learn the MEAN stack by following this tutorial and I have run into an error. Unfortunately, I can't spot out where I went wrong exactly.
I was trying to test routes out in Postman by creating a user but I kept getting back 'Cannot POST /users'.
Can anyone help me out here? Thanks in advance!
routes.js
// Dependencies
var mongoose = require('mongoose');
var User = require('./model.js');
// Opens App Routes
module.exports = function(app) {
// GET Routes
// --------------------------------------------------------
// Retrieve records for all users in the db
app.get('/users', function(req, res){
// Uses Mongoose schema to run the search (empty conditions)
var query = User.find({});
query.exec(function(err, users){
if(err)
res.send(err);
// If no errors are found, it responds with a JSON of all users
res.json(users);
});
});
// POST Routes
// --------------------------------------------------------
// Provides method for saving new users in the db
app.post('/users', function(req, res){
// Creates a new User based on the Mongoose schema and the post bo.dy
var newuser = new User(req.body);
// New User is saved in the db.
newuser.save(function(err){
if(err)
res.send(err);
// If no errors are found, it responds with a JSON of the new user
res.json(req.body);
});
});
};
model.js
// Pulls Mongoose dependency for creating schemas
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// Creates a User Schema. Defines how user data is stored to db
var UserSchema = new Schema({
username : {type: String, required: true},
gender : {type: String, required: true},
age : {type: Number, required: true},
favlang : {type: String, required: true},
location : {type: [Number], required: true}, //[Long, Lat]
htmlverified : String,
created_at : {type: Date, default: Date.now},
updated_at : {type: Date, default: Date.now}
});
// Sets the created_at parameter equal to the current time
UserSchema.pre('save', function(next){
now = new Date();
this.updated_at = now;
if(!this.created_at){
this.created_at = now
}
next();
});
// Indexes this schema in 2dsphere format (critical for running proximity searches)
UserSchema.index({location: '2dsphere'});
// Exports the UserSchema for use elsewhere. Sets the MongoDB collection to be used as:
module.exports = mongoose.model('scotch-user', UserSchema);
server.js
// Dependencies
// -----------------------------------------------------
var express = require('express');
var mongoose = require('mongoose');
var port = process.env.PORT || 3000;
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var app = express();
// Express Configuration
// -----------------------------------------------------
// Sets the connection to MongoDB
mongoose.connect("mongodb://localhost/MeanMapApp");
// Logging and Parsing
app.use(express.static(__dirname + '/public')); // sets the static files location to public
app.use('/bower_components', express.static(__dirname + '/bower_components')); // Use BowerComponents
app.use(morgan('dev')); // log with Morgan
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.urlencoded({extended: true})); // parse application/x-www-form-urlencoded
app.use(bodyParser.text()); // allows bodyParser to look at raw text
app.use(bodyParser.json({ type: 'application/vnd.api+json'})); // parse application/vnd.api+json as json
app.use(methodOverride());
// Routes
// ------------------------------------------------------
require('./app/routes.js')(app);
// Listen
// -------------------------------------------------------
app.listen(port);
console.log('App listening on port ' + port);
I believe this is where your error is.
Instead of:
module.exports = mongoose.model('scotch-user', UserSchema);
Try:
module.exports = mongoose.model('User', UserSchema);
Also, look into using Express.js for your routes. When you are testing on Postman, double check that you are entering all "required" parts for your MongoDB Schema.
I just copied your scripts and I have no problems at all!
Make sure you're using the right methods and routes in postman.
Small tip: Mongoose handles it own schema's, so there is no need to export them.
You can easily do the following
app.js
// Dependencies
// -----------------------------------------------------
var express = require('express');
var mongoose = require('mongoose');
var port = process.env.PORT || 3000;
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var app = express();
// Load all models
require('./app/model');
// Express Configuration
model.js
// remove module.exports in the last line
mongoose.model('User', UserSchema);
routes.js
// Dependencies
var mongoose = require('mongoose');
var User = mongoose.model('User');

Categories