I am practicing API and having a small issue. Can someone please have a look the code below and let me know why req.body logs undefined when I do POST request using angular $http on the client side? also try a simple jquery AJAX request to have the same result.
//------------------ back-end
var express = require('express');
var mongoose = require('mongoose');
var app = express();
//connect DB
var mongoURI = process.env.MONGOLAB_URI || 'mongodb://localhost/Ecomm_db';
mongoose.connect(mongoURI);
//express config
app.use(express.static(__dirname + '/public'));
//DB setup
var Schema = mongoose.Schema;
var Product = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
style: { type: String, unique: true },
modified: { type: Date, default: Date.now }
});
var ProductModel = mongoose.model('Product', Product);
//API
app.post('/api/products', function (req, res){
var product;
console.log("POST: ");
console.log(req.body);
product = new ProductModel({
title: req.body.title,
description: req.body.description,
style: req.body.style,
});
product.save(function (err) {
if (!err) {
return console.log("created");
} else {
return console.log(err);
}
});
return res.send(product);
});
//--------------------------- client-end
$http({
method: 'POST',
url: '/api/products',
data: {
title: "my t-shirts",
description: "super good",
style: "my style"
}
}).then(function (response){
console.log('POST response',response);
}, function (err){
console.log('err:', err);
})
Try to use module 'body-parser'
var bodyParser = require('body-parser');
...
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
Related
I've having issues with both my routes and getting/saving the data with mongodb. It seems to have validation errors when saving or maybe not posting JSON. Any ideas?
Here's my mongoose schema:
// grab the things we need
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// create a schema
var sitesEntrySchema = new Schema({
ip: {
type: String,
required: true,
trim: true
},
domain: {
type: String,
required: true,
trim: true
},
wp: {
type: String,
required: true,
trim: true
},
host_name: {
type: String,
required: true
},
hosted: {
type: Number,
required: true
}
});
// make this available to our users in our Node applications
var Site = mongoose.model('Site', sitesEntrySchema);
module.exports = Site;
And my angular http request
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope, $http) {
$http.get('/api/mongo')
.then(function(response) {
console.log(response.data);
$scope.myData = response.data;
});
});
app.controller('FormCtrl', function($scope, $http) {
$scope.formData = {};
$scope.addSite = function() {
$http.post('/api/create', $scope.formData)
.success(function(data) {
console.log($scope.formData);
$scope.formData = {}; // clear the form so our user is ready to enter another
swal(
'Good job!',
'Site was added!',
'success'
);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
});
My express routes:
var express = require('express');
var router = express.Router();
var Site = require('../models/site');
//Return From Mongo
router.get('/api/mongo', function(req, res) {
Site.find({}, function(err, sites) {
if (err)
res.send(err)
res.send(sites);
});
//res.json({"yo": "yo this shit works"});
});
//Add A Site
router.post('/api/create', function(req, res, next) {
//create object with form input
var siteData = {
ip: req.body.ip,
domain: req.body.domain,
wp: req.body.wp,
host_name: req.body.host_name,
hosted: req.body.hosted
};
// use schema's 'create' method to insert doc into mongo
Site.create(siteData, function(error) {
if (error) {
//return next(error);
res.send(error);
} else {
return res.json({ message: 'Site added!' });
}
});
});
Without specific outputs that show what is going wrong, here are a few things stick out to me. The first is not always responding with json. You should also try using next() to handle your errors since Express will make sure to send back a correct error response. With these changes, your get route looks like:
//Return From Mongo
router.get('/api/mongo', function(req, res, next) {
Site.find({}, function(err, sites) {
if (err) {
next(err)
} else {
return res.json(sites);
}
});
});
Secondly, It is best practice to return the newly created resource, so your create route should look like
//Add A Site
router.post('/api/create', function(req, res, next) {
//create object with form input
var siteData = {
ip: req.body.ip,
domain: req.body.domain,
wp: req.body.wp,
host_name: req.body.host_name,
hosted: req.body.hosted
};
// use schema's 'create' method to insert doc into mongo
Site.create(siteData, function(error, site) {
if (error) {
next(error);
} else {
return res.json(site);
}
});
});
In addition, depending on your version of Angular, you might be using the deprecated promise syntax for the post request. You should be using .then(), not .success() and .error(). This might also be causing an issue.
Lastly, you should try your best to follow REST guidelines for your routes and responses. It will make it much easier to extend your web app and will keep you more organized. Here is a good Express/Node resource for that https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4.
ADDED: Here is an example of how you can log your errors depending on production/development environments
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
console.log('err:', err.status, err.message);
res.status(err.status || 500);
res.json({message: err.messages});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
I am new to MEAN applications.Here I have a REST based sample application using node-restful library in which I can perform operations(get,save,delete) except 'put'. However 'put' operation works well on rest clients (advanced REST, postman) but not on angular client.
mongoose Model
var restful = require('node-restful');
var mongoose = restful.mongoose;
// Schema
var productSchema = new mongoose.Schema({
name: String,
college: String,
age: Number
});
// Return model
module.exports = restful.model('Products', productSchema);
Node-express code
var express = require('express');
var methodOverride = require('method-override');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var cors =require('cors');
// MongoDB
mongoose.connect('mongodb://localhost/rest_test');
var autoIncrement = require('mongoose-auto-increment');
// Express
var app = express();
app.use(methodOverride('_method'));
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Routes
app.use('/api', require('./routes/api'));
// Start server
app.listen(4000);
console.log('API is running on port 4000');
angular function to update the data
$scope.updateData = function (userID) {
$scope.actionData = {
"name": $scope.name,
"college": $scope.college,
"age": $scope.age
}
RoleEditF.updateUserData({
userId: userID
}, $scope.actionData).then(function (response) {
$scope.userData = response;
console.log($scope.userData)
$scope.getData();
}).catch(function (response) {
$scope.error = "Unable to get Files (code: " + response.status + "). Please try later.";
});
}
angular.module('myapp')
.factory('RoleEditF', function (updateS) {
return {
updateUserData: function (parm, data, callback) {
var cb = callback || angular.noop;
return updateS.save(parm, data,
function (res) {
return cb(res);
},
function (err) {
return cb(err);
}.bind(this)).$promise;
}
}
})
Factory to call API
angular.module('myapp')
.factory('updateS',function($resource) {
return $resource('http://localhost:4000/api/products/:userId', { userId: '#userId' }, {
update: {
method: 'PUT'
}
}, {
stripTrailingSlashes: false
});
});
I'm getting following error on browser
"NetworkError: 404 Not Found - http://localhost:4000/api/products/57161e0fe4fbae354407baa3"
it has to be 'update' in
'update': {
method: 'PUT'
}
inside your $resource() factory
documentation here
https://docs.angularjs.org/api/ngResource/service/$resource
under Creating a custom 'PUT' request
This is my Server.js file (NodeJS):
var express = require('express');
var server= require('http');
var path= require("path");
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app= express();
var staticDIR = path.resolve(__dirname, "./www");``
app.use(express.static(staticDIR));
app.use(bodyParser.json());
app.get("*", function (req, res) {
var indexViewPath = path.resolve(__dirname, "./www/index.html");
res.sendFile(indexViewPath);
});
var dbURI = 'mongodb://localhost:27017/mydatabase';
mongoose.connect(dbURI);
mongoose.connection.on('connected', function () {
console.log('Mongoose connected to ' + dbURI);
});
mongoose.connection.on('error',function (err) {
console.log('Mongoose connection error: ' + err);
});
mongoose.connection.on('disconnected', function () {
console.log('Mongoose disconnected');
});
process.on('SIGINT', function() {
mongoose.connection.close(function () {
console.log('Mongoose disconnected through app termination');
process.exit(0);
});
});
var userSchema = new mongoose.Schema({
name: String,
password:String,
email: {type: String, unique:true},
createdOn: { type: Date, default: Date.now }
//modifiedOn: Date,
//lastLogin: Date
});
mongoose.model( 'User', userSchema );
var User = mongoose.model('User');
var CompanySchema = new mongoose.Schema({
CompanyName: String,
password:String,
email: {type: String, unique:true},
createdOn: { type: Date, default: Date.now }
//modifiedOn: Date,
//lastLogin: Date
});
mongoose.model( 'company', userSchema );
var company = mongoose.model('company');
User.find({}, function(err, users) {
if(!err){
console.log(users);
}
});
company.find({}, function(err, users) {
if(!err){
console.log(users);
}
});
app.post('/account', function(req, res){
new company({
CompanyName:req.body.Company,
email:req.body.email,
password:req.body.password
}).save(function(err,doc){
if(err)res.json(err);
else res.send("succesfully inserted");
console.log(res);
});
});
This is my Middleware to get tha data:
app.get('/details', function (req, res) {
console.log('I received a GET request');
company.find({}, function(err, users) {
if(!err){
console.log(users);
}
else{
res.render('/details',{users:docs})
}
});
});
app.listen(9000);
console.log("Server Running on port 3000");
This is my Controller.js (AngularJS) file:
angular.module('myApp', ['ngMaterial','firebase','ui.router'])
.controller('detailsCtrl', function($scope,myfirebaseAddress,$location,$timeout) {
var ref = new Firebase(myfirebaseAddress);
})
This is my route where I want to show the mongoDb saved data
<ui-view>
<div class="sub-header">
<h3>Company Details</h3>
</div>
<ul>
<li ng-repeat="users in user">
{{user.email}}
</li>
</ul>
</ui-view>
Thanks in advance
instead if writing below code
if(!err){
console.log(users);
}
else{
res.render('/details',{users:docs})
}
do like this
if(!err){
res.send(users);
}
else{
res.send('could not retrived data');
}
in controller side you can get your all data inside success call back function.here also check
app.listen(9000);
console.log("Server Running on port 3000");
this should like below.
app.listen(9000);
console.log("Server Running on port 9000");
Controller to get the requested data
.controller('detailsCtrl', function($scope,$http) {
$scope.users = [];
$http.get('/details').then(function(d)
{
console.log(d);
$scope.users= d.data;
},function(err)
{
console.log(err); }
)
})
server route
app.get('/details', function (req, res) {
console.log('I received a GET request');
company.find({}, function(err, users) {
if(!err){
res.json(users);
}
});
});
If you want to retrieve your data, you must stop this:
res.render('/details',{users:docs})
If you want to serve data with an angular app, you have to stop to render a view and start to give back a json in your response.
res.jsonp(users)
Then you've to adjust your controller.
Write a service like:
angular.module('yourApp')
.service('userService', function($http){
return {
getUsers: function(url) {
return $http.get(url)
}
}
})
this should return an http promise.
In your controller you handle this promise this way:
$scope.users = function(){
userService.getUsers('/users')
.then(function(users){
//You have your users object
})
}
remember to handle the unsuccesfull case of your promise
Try to use the angular http module to get the node/express response that get the data from mongodb in client side; like this: https://github.com/J-Alex/api_rest_mvc
In the view html page there is a form with a table and when i submit the form two objects are created cvm and schedules for form and table. i somehow want schedules(which is an array) to be related to cvm form. so i tried this way...
Here is the defined model
$scope.addSchedule=function(schedule)
{
console.log(schedule.startDate);
console.log(schedule.location);
$scope.schedules.push({
startDate: schedule.startDate,
location: schedule.location
});
schedule.startDate='';
schedule.location='';
};
var inData={'cvm': $scope.cvm,'schedules': $scope.schedules};
$scope.addCvm=function()
{
console.log($scope.cvm);
console.log($scope.schedules);
$http.post('/cvmApi',inData).success(function(response) {
console.log(response);
refresh();
});
};
sever side Connection
i guess somthing i missed in this part
/* POST */
router.post('/', function(req, res, next)
{
console.log("Cvm api post '/'");
console.log("retrieving:: " + req.body);
cvmModel.create(req.body, function (err, post) {
console.log("saving:: " + post);
if (err) return next(err);
res.json(post);
});
});
Here is my schema for mongodb
'use strict';
var mongoose = require('mongoose');
var cvmSchema = new mongoose.Schema({
visitOrganization: { type: String },
visitAgenda: { type: String },
accountManager: { type: String },
visitCoordinator: { type: String },
schedules:[{
startDate: String,
location: String
}]
});
module.exports = mongoose.model('visit', cvmSchema);
plz help !! thanks in advance
I think you should try with below change :
//Change addCvm function
$scope.addCvm = function(){
var inData = $scope.cvm;
inData.schedules = $scope.schedules;
console.log(inData);
$http.post('/cvmApi',inData).success(function(response) {
console.log(response);
refresh();
});
};
// Server Side API Code
router.post('/cvmApi', function(req, res, next) {
console.log("Cvm api post '/'");
console.log("retrieving:: " + req.body);
cvmModel.create(req.body, function (err, post) {
console.log("saving:: " + post);
if (err) return next(err);
res.json(post);
});
});
The thing is i dint realize my variable startDate was not in type string in my html page as i was using some date plugins....
soo ya thats it worked brilliantly ...
addCvm function in controller thanks to rana ;-)
$scope.schedules=[];
$scope.addCvm = function(){
var inData = $scope.cvm;
inData.schedules = $scope.schedules;
console.log(inData);
$http.post('/cvmApi',inData).success(function(response) {
console.log(response);
refresh();
});
};
server side Api
router.post('/', function(req, res, next) {
console.log("Cvm api post '/'");
console.log("retrieving:: " + req.body);
cvmModel.create(req.body, function (err, post) {
console.log("saving:: " + post);
if (err) return next(err);
res.json(post);
});
});
may be not required but i changed my schema though....
var cvmSchema = new mongoose.Schema({
visitOrganization: { type: String },
visitAgenda: { type: String },
accountManager: { type: String },
visitCoordinator: { type: String },
schedules: [{
dateStart: { type:String },
locationHere: { type: String }
}]
});
I am trying to upload multipart/form-data for a simple MEAN stack application. When putting everything in one file and running it it works fine.
Server.js
var express = require('express');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
switch(file.mimetype) {
case 'image/jpg' :
case 'image/jpeg':
case 'image/gif':
var extension = file.mimetype.split("/");
extension = extension[extension.length-1];
break
case 'video/quicktime':
var extension = 'mov';
break
case 'video/mp4':
var extension = 'mp4';
break
default:
var extension = 'jpeg';
}
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
});
var upload = multer({ storage: storage });
var path = require('path');
var app = express();
var segmentUpload = upload.fields([{ name: 'segmentVideo', maxCount: 1}, { name: 'segmentStill', maxCount: 1}, { name: 'segmentGif', maxCount: 1}])
app.post('/photos/upload', segmentUpload, function (req, res, next) {
console.log(req);
console.log(req.files['segmentVideo'][0]);
console.log(req.files['segmentStill'][0]);
console.log(req.files['segmentGif'][0]);
console.log(req.body.title);
});
app.get('/', function(req, res) {
res.sendfile('./index.html');
});
app.listen(8080);
console.log("App listening on port 8080");
index.html
<body>
<form action="/photos/upload" method="post" enctype="multipart/form-data">
title: <input type="text" name="title"> <br><br>
Select video to upload:
<input type="file" name="segmentVideo" id="fileToUpload"> <br><br>
Select jpeg to upload:
<input type="file" name="segmentStill" id="fileToUpload"><br><br>
Select gif to upload:
<input type="file" name="segmentGif" id="fileToUpload"><br><br>
<input type="submit" value="Upload Image" name="submit">
</form>
But when I try to integrate multer into my node routing I cannot get my app to accept the multipart/form-data.
app/routes.js
var Video = require('./models/video');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
switch(file.mimetype) {
case 'image/jpg' :
case 'image/jpeg':
case 'image/gif':
var extension = file.mimetype.split("/");
extension = extension[extension.length-1];
break
case 'video/quicktime':
var extension = 'mov';
break
case 'video/mp4':
var extension = 'mp4';
break
default:
var extension = 'jpeg';
}
console.log("new extension: " + extension);
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
});
var upload = multer({ storage: storage });
module.exports = function(app) {
// api --------------------------------------
// get all todos
app.get('/api/videos', function(req,res){
// use mongoose to get all todos in the database
Video.find(function(err, videos){
// if there is an error, send the error
if (err)
res.send(err);
res.json(videos);
});
});
var segmentUpload = upload.fields([{ name: 'segmentVideo', maxCount: 1}, { name: 'segmentStill', maxCount: 1}, { name: 'segmentGif', maxCount: 1}])
app.post('/api/videos', segmentUpload, function(req, res){
// create a video
Video.create({
title : req.body.title,
description : req.body.description,
category : req.body.category,
day : req.body.day,
videoUrl : req.body.videoUrl,
stillUrl : req.body.stillUrl,
gifUrl : req.body.gifUrl,
airReady : false
}, function(err, video) {
if (err)
res.send(err)
// get and return all the todos after you create another
Video.find(function(err, videos){
if (err)
res.send(err)
res.json(videos);
});
});
});
// delete a todo
app.delete('/api/videos/:video_id', function(req,res){
Video.remove({
_id : req.params.video_id
}, function(err, video) {
if (err)
res.send(err);
// get and return all the todos after you delete one
Video.find(function(err, videos) {
if (err)
res.send(err)
res.json(videos);
});
});
});
// edit a todo
app.put('/api/videos/:video_id', function(req,res){
Video.findByIdAndUpdate(req.params.video_id,
{ $set: { title: req.body.title
}},
function(err, video){
if (err)
res.send(err)
// get and return all todos after edit
Video.find(function(err, videos){
if (err)
res.send(err)
res.json(videos);
});
});
});
// find -------------------------------------------------------------
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
};
I receive an error:
TypeError: Cannot read property 'title' of undefined
This is my first post to stack overflow, but I appreciate all of the support!
The problem might be due to use are sending the multipart/form-data but you are not converting it to json and you are using json for retrieving the data.
Use body-parser
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());