getting empty array from Angular http.post service - angularjs

My '/messages' API is used to query mongodb for document with given 'hostname' and 'day'. When I test it with 'postman' I got correct response, array of objects. But when angular client used, it gives me empty array [], why?
Controller
apiSvc.post('/messages', {hostname: "XYZ", day: '1'})
.then(function (response) {
console.log(response.data);
});
SERVICE
.factory("apiSvc", function($http) {
return {
post: function(url,data) {
return $http.post(url,data);
},
}
})
ROUTER
router.post('/messages', function (req, res, next) {
console.log(req.body.hostname, req.body.day);
Message.find({day: req.body.day, hostname: req.body.hostname},
function(err, message) {
res.send(message);
});
});

Related

POST, PUT, DELETE requests from AngularJS $http/AJAX to Node.js + Express.js based API

I wrote backend API on Node.js and Express.js v4, this part (index.js):
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://example.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.post('/add1', function (req, res) {
db.one("INSERT INTO table(value1) VALUES (${value1}) RETURNING ID", req.query).then(function (data) {
res.json(data);
}).catch(function (error) {
res.json(error);
});
});
app.put('/add2', function (req, res) {
db.one("INSERT INTO table(value1) VALUES (${value1}) RETURNING ID", req.query).then(function (data) {
res.json(data);
}).catch(function (error) {
res.json(error);
});
});
app.get('/add3', function (req, res) {
db.one("INSERT INTO table(value1) VALUES (${value1}) RETURNING ID", req.query).then(function (data) {
res.json(data);
}).catch(function (error) {
res.json(error);
});
});
And I have Angular JS or sample ajax like this
app.controller('globalController', function($scope, $http) {
var jsd = {};
jsd.value1=1;
$http.put(API_URL + 'add2', jsd).then(function(data) {
console.log(data);
}, function(data) {
console.log(data);
});
});
and
$.ajax({
url: API_URL + 'add1',
method: 'POST',
dataType: 'json',
data: jsond,
success: function(data) {
console.log(data);
},
error: function(data) {
console.log(data);
}
});
But I don't recive any data to my req.query and in generally in req object. When I make my AJAX request to add3 with get, then all works, req.query has my params.
I read about this solution:
app.config(function ($httpProvider) {
$httpProvider.defaults.transformRequest = function(data){
if (data === undefined) {
return data;
}
return $.param(data);
};
$httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});
and solution here
var multer = require("multer");
//...
var upload = multer({ dest: "./upload/" });
app.post("/post", upload.array(), function(req, res) {
console.log(req.body);
res.send(null);
}
I tried first, not works, and second is too strange solution (I can't save data to files and etc.) I think problem was in fist OPTION request, but I googled it, not found solution. I need little example (working code) how I can send POST or PUT data from Angular $http or AJAX and use this data in req object in node.js. In GET requests all this works, but how I can make it work on others?
Which version of Express are you using? It's possible that you're writing the old way and using the new version.
You might wanna check this out -- How to retrieve POST query parameters?
Anyway, I'd suggest you use ngResource for making REST HTTP calls in Angular.
Instantiate the Factory
This will expose a few methods e.g query, save etc.
angular
.module('MyModule')
.factory('AddEndpoint', AddEndpoint);
AddEndpoint.$inject = ['$resource'];
function AddEndpoint($resource) {
return $resource(API_URL + '/:param', { param: '#param' });
}
Enjoy The Factory
angular
.module('MyModule')
.controller('MyController', MyCtrl)
MyCtrl.$inject = ['AddEndpoint'];
function MyCtrl(AddEndpoint) {
var scope = this;
scope.getFromApi = AddEndpoint.get({ params: 'add1' }); // GET 'API_URL/add1'
scope.postToApi = postToApi;
function postToApi(data) {
data.params: 'add2'
AddEndpoint.save(data); // POST to 'API_URL/add2'
}
}

Pass user messages depending on request response

Introduction
OK, what I have is a app built in Node and Angular. I pass A users email to my backed using a post in Angular, from the backed the order in the backed is:
Get the email
Get API key
Post email and API key to API
I do this by posting email to backed then using node and express get email use promise resolve (first function) to pass the email to my third function as well as the API key retrieved from the second function.
What I need
Angular post to back end Node
Run first function, If first function has retrieved the email then run function 2. if not correct then pass information to the first post (Angular) to display message.
Run second function, if true run function 3
Finally run post with data collected from function 1 and 2, if post correctly pass 200 code to first function or pass to angular post.
Needed
Verification on the front end (Angular) on each step (function 1, 2 and 3 in Node) they can be response code so that I may print a different message depending on response code
Objective
A user post email on front end, then depending on if the email was accepted on the API let the user know, This is where different messages or redirects come in to play depending if it was a wrong or right email.
My Code
Angular side
This is where the first post to the Node back end happens, would be nice if this could get different response request depending on the results on the back-end.
var firstFunction = function () {
return new Promise(function (resolve) {
setTimeout(function () {
app.post('/back-end/controller', function (req, res) {
console.log(req.body);
var login = req.body.LoginEmail;
res.send(login);
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
};
Node side (all in controler.js)
First function
I would like this to trigger function 2 if success if not send a response code back to the Angular request.
var firstFunction = function () {
return new Promise(function (resolve) {
setTimeout(function () {
app.post('/back-end/controller', function (req, res) {
console.log(req.body);
var login = req.body.LoginEmail;
//Promise.all([firstFunction(), secondFunction()]) .then(thirdFunction);
//res.send(login);
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
};
Second function
This function gets API key, if This function is successful trigger function three.
var secondFunction = function () {
return new Promise(function (resolve) {
setTimeout(function () {
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
DEBUG: false
}, function (err, client) {
if (err) {
// Authentication failed
console.error("Authentication Failed", err);
} else {
// Authentication successful
var api_key = client.apiKey;
console.log("Authentication successful !", api_key);
resolve({data_api: api_key});
}
});
console.error("Second done");
}, 2000);
});
};
Third Function
If second function passes then this function should run using the email from the first and the API key from the second, If success then pass pass success back to first function to pass give 200 success to the angular side, or directly send a request response to Angular, If fail then again let the front end know.
function thirdFunction(result) {
return new Promise(function () {
setTimeout(function () {
var headers = {
'User-Agent': 'Super Agent/0.0.1',
'Content-Type': 'application/x-www-form-urlencoded'
};
// Configure the request
var api = result[1].data_api;
var login_email = result[0].data_login_email;
var options = {
url: 'https://pi.pardot.com/api/prospect/version/4/do/read',
method: 'POST',
headers: headers,
form: {
'email': login_email,
'user_key': userkey,
'api_key': api
},
json: true // Automatically stringifies the body to JSON
};
// Start the request
rp(options)
.then(function (parsedBody) {
console.info(login_email, "Is a user, login pass!");
// router.redirect('/login'); // main page url
// res.send.status(200);
})
.catch(function (err) {
console.error("fail no such user");
// res.status(400).send()
});
console.error("Third done");
}, 3000);
}
);
}
Promise.all([firstFunction(), secondFunction()]) .then(thirdFunction);
If anyone knows how to do this please can you help, this is the last part of my app i need to get working, Thanks.
Summery
In summery I would like different response codes Angular side depending on where and when the function got to on backed or if it passed all three functions.
Eg:
request code for fails to post to backed
Fails to get API key on function 2
Fails to send email to API on third function
Email not present on API
Email present on API and all pass, Your In !!
UPDATE
I found I can pass a message back to my Angular post using the following, but how can I make this message different depending on what function has run ?
var firstFunction = function () {
return new Promise(function (resolve) {
setTimeout(function () {
app.post('/back-end/controller', function (req, res) {
console.log(req.body);
// res.status(500).send({ error: "boo:(" });
res.send('hello world');
var login = req.body.LoginEmail;
res.send(login);
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
};
I solved this by merging 2 function into one (the retrieve function and post) then i changed the promise chain
var firstFunction = function () {
return new Promise(function (resolve) {
setTimeout(function () {
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
DEBUG: false
}, function (err, client) {
if (err) {
// Authentication failed
console.error("Authentication Failed", err);
} else {
// Authentication successful
var api_key = client.apiKey;
console.log("Success your API key is", api_key);
resolve({data_api: api_key});
}
});
}, 2000);
});
};
var secondFunction = function (result) {
return new Promise(function () {
setTimeout(function () {
app.post('/back-end/controller', function (req, res) {
console.log(req.body);
var login = req.body.LoginEmail;
var api = result[0].data_api;
var headers = {
'User-Agent': 'Super Agent/0.0.1',
'Content-Type': 'application/x-www-form-urlencoded'
};
var options = {
url: 'https://pi.pardot.com/api/prospect/version/4/do/read',
method: 'POST',
headers: headers,
form: {
'email': login,
'user_key': userkey,
'api_key': api
},
json: true // Automatically stringifies the body to JSON
};
if (login.length !== 0) { // maybe use node email validation ?
console.log("Email Accepted, Next posting to API.......");
rp(options)
.then(function (parsedBody) {
console.info(login, "Is a user, login pass!");
res.status(200).send({ user: login });
})
.catch(function (err) {
console.error("fail no such user");
res.status(400).send('fail to login');
});
} else {
console.log("Failed to get email from front end");
res.status(404).send('Incorrect length');
}
});
});
});
};
Promise.all([firstFunction()]).then(secondFunction);

MEAN stack - GET and POST not querying or saving to mongodb

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: {}
});
});

angularjs using ng-resource to node.js back-end not sending correct POST request

I would like to make a POST request to my node.js server (using express) from my angularjs app. I'm having troubles to send the correct {key:value}. Despite hours on researching the solution, I don't know how to write correctly the params to get them back on the server side . My results is : '{"key":"value"}': ''. Where am I wrong ?
Any help appreciated, thanks!
client.js
module.factory("Friends", function($resource) {
return $resource("https://myUrl/:id", {'id': '#id'} ,{
mes: {method: 'POST', headers: {'content-Type': 'application/x-www-form-urlencoded'} , isArray : false }
});
});
module.controller('communityCtrl', ['$scope','$rootScope', 'Friends', function($scope,$rootScope, Friends) {
var value = "aValue";
$scope.getData = function()
{
Friends.mes({id: 'jb'}, {key : 'value'} ).$promise.then(function(data){
console.log(data);
});
}
}]);
server.js
app.post('myUrl/jb', function(req, res) {
console.log("req.body : ", req.body);
res.json({code: 0, message: req.body.msg || ""});
});
output
req.body : { '{"key":"value"}': '' }
Have you tried $http?
Factory definition:
module
.factory('friendsFactory', ['$http', function ($http) {
return {
post: function (id, data) {
return $http.post('https://myUrl/' + id, data);
},
get: function () {
return $http.get('https://myUrl/');
}
};
}]);
From within your controller:
module
.controller('friendsController', ['friendsFactory', function (friendsFactory) {
friendsFactory.post(1, {id: 1})
.then(function (res) {
// success
console.log(res.data);
})
.catch(function (err) {
// there has been an error
console.error(err.data);
});
}]);
Within your node.js API endpoint, req.body will either be a string, or an object.
Note: if it is a string, ensure that you are using the body-parser middleware on express.
On the node server:
var express = require('express')
, bodyParser = require('body-parser')
app = express();
app.use(bodyParser.urlencoded({extended: true});
The body-parser middleware (amongst other things) takes the payload in req.body and replaces it a valid java object representation of that data.
TL;DR Your problem
The issue you have in your code is likely the following line:
Friends.mes({id: 'jb'}, {key : 'value'} ).$promise.then(function(data){
Try changing it to:
Friends.mes({id: 'jb', key: 'value'}).$promise.then(function(data){
Once you've done this, the req.body object on the server route will contain the following {id: 'jb', key: 'value'} instead of { '{"key":"value"}': '' }.
Example $resource application:
I've created a small example of using $resource to GET and POST to an API.
./public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-resource.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="friendController as vm">
<div>
{{vm.friend}}
</div>
<button ng-click="vm.getFriend()">Get User</button>
<button ng-show="vm.friend" ng-click="vm.messageFriend(vm.friend)">Message Friend</button>
</body>
</html>
./public/script.js
angular.module('app', ['ngResource'])
.factory('friendFactory', ['$resource', function ($resource) {
return $resource(
'/api/v1/friends/:id',
{id: '#_id'},
{
mes: {
method: 'POST',
headers: {'content-Type': 'application/x-www-form-urlencoded'},
isArray : false,
params: { message: true }
}
}
);
}])
.controller('friendController', ['friendFactory', function (friendFactory) {
var vm = this;
vm.friend = null;
vm.getFriend = _getFriend;
vm.messageFriend = _messageFriend;
function _getFriend() {
friendFactory.get({id: 1})
.$promise
.then(function (res) {
console.log(res);
vm.friend = res;
});
}
function _messageFriend(friend) {
/* method 1: call $mes on a friend object: */
// vm.friend.$mes({message: 'A message'})
// .then(function (friend) {
// vm.friend = friend;
// });
/* method 2: call mes on the resource: */
friendFactory.mes({_id: 1, message: 'A message'})
.$promise
.then(function (friend) {
vm.friend = friend;
});
}
}]);
index.js - the node.js server hosting the page and exposing a simple api
var express = require('express')
, path = require('path')
, app = express()
, bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
app.use(express.static(path.join(__dirname, './public')));
var friends = [
{ _id: 0, name: 'A' },
{ _id: 1, name: 'B' },
{ _id: 2, name: 'C' },
{ _id: 3, name: 'D' }
];
app.get('/api/v1/friends', function (req, res) {
return res.send(friends);
});
app.get('/api/v1/friends/:id', function (req, res) {
for (var i = 0; i < friends.length; i++) {
if (friends[i]._id == req.params.id) return res.send(friends[i]);
}
return res.status(404).send('Not found');
});
app.post('/api/v1/friends/:id', function (req, res) {
for (var i = 0; i < friends.length; i++) {
if (friends[i]._id == req.params.id) {
friends[i].message = req.query.message;
return res.send(friends[i]);
}
}
return res.status(404).send('Not found');
});
app.listen(8080, function () {
console.log('Server running');
});
This example has a simple API that allows you to
GET a list of friends
GET a single friend
POST a message to a friend (I am assuming this is what your mes stands for?). When posting - message will be available as a querystring parameter (req.query.message) or in the body (req.body.message).
In this example, it simple appends 'message' to the friend and returns the object.
Things to note (In friendController):
Calling $mes on an existing friend object returns a promise by default, so no need to chain .$promise.
Calling mes on the resource itself does not return a promise, so $promise is required.

Post call for search data

Here i need to search name in scroll,for that i send search data query string in get call but i need to that in post.
Here is my server and client controller route and service.Also here i handling search from server side.How to post data which user has been searched ,and pass that to client and server side.
client controller service:
'use strict';
angular.module('details').factory('DetailService', ['$resource',
function($resource) {
return $resource('details', {
},
searchUsers:{
method: 'GET',
}
});
}
]);
Angular controller:
$scope.searchServer = function(searchData){
DetailService.searchUsers({search:searchData},function(response){
}, function(error){
$scope.status = 'Unable to load customer data: ' + error.message;
});
}
my Server side controller:
exports.searchCust = function (req, res) {
var strWhere = {
corporateName: search
};
db.Customer.findAll({
where: [strWhere],
}).then(function (customers) {
if (!customers) {
return res.status(400).send({
message: 'Customer not found.'
});
} else {
res.jsonp(customers);
}
})
};
my server sideroute:
app.route('/details').all(customersPolicy.isAllowed)
.get(details.searchCust);
app.param('search', details.searchCust);
};
I didn't try it out in all details as it looks like it was copy and pasted together without reading the basics. However, if you want POST requests, you need to set them both in the node-code and the Angular code, see below. What's more, Angular doesn't use JSONP, it uses JSON, so you need to set that. In the searchUsers-resource-call you only implemented the error-branch, so the results would just vanish. You'll find them in $scope.searchResults now.
client controller service:
'use strict';
angular.module('details').factory('DetailService', ['$resource',
function($resource) {
return $resource('details', {},
searchUsers: {
method: 'POST',
}
});
}]);
Angular controller:
$scope.searchServer = function(searchData) {
DetailService.searchUsers({
search: searchData
}, function(response) {
$scope.status = "OK";
$scope.searchResults = response;
}, function(error) {
$scope.status = 'Unable to load customer data: ' + error.message;
});
}
my Server side controller
exports.searchCust = function(req, res) {
var strWhere = {
corporateName: search
};
db.Customer.findAll({
where: [strWhere],
}).then(function(customers) {
if (!customers) {
return res.status(400).send({
message: 'Customer not found.'
});
} else {
res.json(customers);
}
})
};
my server sideroute:
app.route('/details').all(customersPolicy.isAllowed)
.post(details.searchCust);
app.param('search', details.searchCust);
};

Resources