Data is not passed from AngularJS controller to NodeJS server - javascript

I am attempting to pass some values from my client-side AngularJS script to a server-side NodeJS script. I set up the POST request like so:
$scope.addUser = function() {
console.log($.param($scope.user));
$http({
method: 'POST',
url: '/addUser',
data: $.param($scope.user),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).
success( function(response) {
console.log("success");
}).
error( function(response) {
console.log("error");
});
};
The $scope.user variable is { name: "john", email: "doe" }, and evaluates to name=john&email=doe when passed through $.param($scope.user). I originally thought the problem was the content-type of the request, which was originally a JSON object. After reading about similar problems I changed the content-type to x-www-form-urlencoded, but still could not grab the data from the POST request.
Here is the server-side NodeJS script that is hit with the POST request:
app.post('/addUser', function(req, res) {
console.log(req.params);
});
I know the server-side script is being reached, as I can print out data such as req.method, but attempting to print req.params results in just { }.
Why are my POST parameters not going through?

Request bodies are not saved to req.params. You need to add a middleware to parse the request body for you. req.params is for key=value pairs supplied as part of the URL (e.g. POSTing to "/foo/bar?baz=bla" would result in req.params.baz === 'bla').
Some example solutions:
body-parser - parses only application/json and application/x-www-form-urlencoded request bodies.
formidable - parses application/json, application/x-www-form-urlencoded, and multipart/form-data. This is what was used in the body parser in Express 3. I'm not sure if there is an "official" Express middleware for it for Express 4.
busboy - parses application/x-www-form-urlencoded and multipart/form-data. It does not save files to disk itself, but instead presents files as readable streams. The API differs from formidable(/body parser from Express 3). There are a few Express middleware available for busboy:
connect-busboy - a thin wrapper that merely sets up a Busboy instance on your req. You can set it to automatically start parsing the request, or you can pipe the request manually to req.busboy when you want to start.
multer - provides an interface more similar to the Express 3 body parser middleware (with req.body and req.files set).
reformed - a new module that provides a layer on top of Busboy to provide mechanisms similar to formidable (e.g. saving uploaded files to disk) but also other features such as field validation.

Since you are using express.js your POST fields are received as part of the body not the URL so you need use body instead of params:
app.post('/addUser', function(req, res) {
console.log(req.body);//also possible req.body.name | req.body.email
});
How about trying a simpler POST something like this (for testing purposes only):
$http.post('/addUser',{ "name": "john", "email": "doe" }).success(function(response) {
console.log("success");
}).error(function(err){
console.log("failure")
});
Please note that Params are used as URL parameters; something like this:
app.get('/addUser/:userID', function(req, res) {
console.log(req.params.userID);
});

Related

How to extract req.body on the server side (I'm using fetch)?

I'm making a project that consists of separate frontend and backend. From the frontend, I make a POST request via fetch that should send a string 'ORANGE' to the backend and then the backend should log it to the console. I can't get the backend to console log the string. I looked at the request in devtools and the string 'ORANGE' was buried there under 'Request payload'. The request itself was sent alright. How do I actually access the string so I can do things with it? (eg, store in database)
//FRONTEND
const commentForm = document.getElementById("editform");
commentForm.addEventListener('submit', function(e) {
e.preventDefault();
fetch('http://localhost:3000/posts/:id', {
mode: 'cors',
method: 'post',
headers: {
"Content-type": "text/plain;charset=UTF-8"
},
body: "ORANGE"
}).then(function(response) {
if (response.ok) {
console.log("response.ok was true: "+ response)
} else {
let error = new Error(response.statusText)
error.response = response
throw error
}
})
});
//BACKEND
router.post('/posts/:id', function(req, res, next) {
console.log('What do I put here to get ORANGE logged?!')
//On the server side I tried some console.log tests.
//console.log("req is " + req); //req is [object Object]
//console.log("type of req is " + typeof req); //type of req is object
//console.log(JSON.parse(req)); //SyntaxError: unexpected token o in JSON at position 1
res.send('whatever. I want ORANGE.')
}
Try for the following:
Use body parser in your server.js file.
Send post request as content-type as json as follows,
headers: { Content-Type: application/json }
and body should be a JSON
body: {"color":"ORANGE"}
In your route just print
console.log(req.body.color)
Express won't, by default, process the body of a request. You need to load a module to do so explicitly.
Since you are using plain text, you can use the body-parser module. This will create a body property on the request:
const bodyParser = require('body-parser');
router.use(bodyParser.text({type: 'text/plain'}))
router.post('/posts/:id', function(req, res, next) {
console.log(req.body);
res.send('Response')
});
Note, however, that it is generally better to use a structured data format like JSON rather than plain text.
In Express 4.16 body-parser module isn't necessary anymore. All you need for getting the body is:
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
Use "Content-type": "application/x-www-form-urlencoded" inside the fetch otherwise CORS will send preflights and give you a hard time. (for more on this google CORS simple request requirements).
As in the documentation of fetch() explained:
This is just an HTTP response, not the actual JSON. To extract the JSON body
content from the response, we use the json() method (defined on the Body mixin,
which is implemented by both the Request and Response objects.)
const response = await fetch('http://example.com/movies.json');
const myJson = await response.json();
console.log(JSON.stringify(myJson));
so you don't have a body object inside your response, only a json object, which is your body.

Body-parser to avoid "JSON.parse(body)"

In express I can use a middleware called "body-parser" to automatically parse the incoming body.
Now that I do not have an express router to apply the middleware to, is it possible to somehow apply it to all requests in my chai test file? So that I can achieve the DRY principle.
I currently use this in every test:
it('login', done => {
request.post('http://localhost:3000', (err, res, body) => {
JSON.parse(body) // <-- I have to parse the body each time
done();
})
});
I'm assuming you are using the Request library. And if I'm understanding your question correctly, you want request to automatically parse your response body via JSON.parse.
The documentation explains how to do that under https://github.com/request/request#requestoptions-callback
json - sets body to JSON representation of value and adds Content-type: application/json header. Additionally, parses the response body as JSON.
So your code should be something like:
request.post({url: 'http://localhost:3000', json: true}, (err, res, body) => {
console.log(res)
console.log(body)
})
Untested, but that's what I gather from reading the docs.

Axios POST params show empty on server - using MERN stack

I want to update a document in Mongo, but when I send an Axios POST request to the server with params for the updates I receive nothing but a blank object on the server side - I'm using Node.js with an Express server (MERN stack).
I have tried the qs library module and Node's querystring module. I tried including headers with
'Content-Type': 'application/x-www-form-urlencoded' and 'application/json'.
My Axios POST request:
const A = 1;
const B = 2;
const data = { A, B };
console.log(qs.stringify(data)); // A=1&B=2
axios.post(url('upVote'), qs.stringify(data));
The server route:
app.post('/upVote', async (req, res) => {
console.log(req.params); // {}
await DB.updateVote(ID, collection, voteCount);
res.end();
});
The headers as shown by Chrome's DevTools.
... Also, all my axios.get() requests work fine and grab data from Mongo and send it back to my app properly, and the url/endpoints match.
There are a couple of ways to send data to the server with axios.
I see the confusion with the documentation in axios, I have not seen this usage before and it does seem to be broken upon looking at the request logs and object.
1) axios.post receives body of the request as a second parameter. So if you want to pass parameters to axios, you should do something like this:
const B = 2;
const data = { A: 1, B: 1 };
axios.post(url('upVote'), {}, { params: data });
Note that axios will handle stringification on it's own and that the third parameter is a config object.
On the server the params will be available at request.query
2) If you want to stringify the parameters yourself, then you should append them into your URL like so
axios.post(`url('upVote')?${qs.stringify(data)}`);
Same here, data on the server will be under request.query
3) It's generally better to use the body of the post request to transfer large data payloads for convenience. You should also consider what your caching strategies are and if they rely on request url without the consideration of request body it may be a concern.
axios.post(url('upVote'), data);
In this case data on the server will be under request.body
UPD: Originally forgot to mention that you will need a body-parser middleware to access request.body.
4) You can use axios without method shorthands which may be useful for some people
axios({
method: 'POST',
url: url('upVote'),
params: data
})
This is identical to the example in 1.
And all of them return a Promise which you can .then().catch() or await.
I think you want .body instead of .params.As you are sending data in body by post using axios. You are printing params which will print nothing for this url/api .
Try
console.log(req.body) // instead of req.params
If this did not work then please show us your react code.
Moreover
In react you have to add .then() after axios else it will say unhanded promise
To get params on server side you have to make some changes
In axios (react)
axios.post(url('upVote/param'), qs.stringify(data));
In server
app.post('/upVote/:params', async (req, res) => {
console.log(req.params)
.....
})
I think you are calling res.end(). I think it should be res.send(...)
This answer should help: https://stackoverflow.com/a/29555444/1971378

Crossdomian ajax requests to server returned json object shows error Unexpected token :

I am running an express server in which I am checking for get requests to certain url requests. Now in the reply I am trying to send a reply in json format so that I can make ajax calls to the page and get data. Now to make cross domain requsts I had to use jsonp. Now when the request is completed and the data is returned to the callback it shows error Uncaught SyntaxError: Unexpected token :.
Here are the server and client codes below
Server
var express=require('express');
var app = express();
var http = require('http').Server(app);
var port=Number(3000);
var server_ip_address = '127.0.0.1';
http.listen(port,server_ip_address, function(){
console.log('listening on '+port);
});
app.get('/test', function (req, res) {
console.log(req.query);
res.send({message:'hello'});
});
Client
$.ajax({
url: 'http://localhost:3000/test',
type: 'GET',
dataType:'jsonp',
crossDomain:true,
data: {
username: $('#username').val(),
password: $('#pwd').val()
},
success: function(result){
console.log($.parseJSON(result));
},
jsonp:'jsonp'
});
In the server code i have tried using
res.setHeader('Content-Type', 'application/javascript');
res.send({message:'recieved'});
even
res.setHeader('Content-Type', 'application/json');
res.send({message:'recieved'});
In the client i have tried logging the result object as it is but to no avail. Any help is appreciated. Moreover any suggestions to use other methods to fetch data are equally welcome. Thanks in advance.
The simplest way to do this is just use res.jsonp() rather than setting your own headers etc:
app.get('/test', function (req, res) {
console.log(req.query);
res.jsonp({message: 'hello'});
});
The default callback parameter is just callback but you can change it (if you need to) like so:
app.set('jsonp callback name', 'cb');
note: You might have to remove the jsonp:'jsonp' from your client-side code as that assigned the name of the callback. I'd also suggest you swap it from a GET to a POST request if you are submitting data (especially sensitive data).

Get Dropbox OAuth Token from Code via request.js Fails; Equivalent curl Works

I'm trying to exchange my Dropbox oauth code for a token as per the http api documentation.
When I perform the command with curl thusly:
curl https://api.dropbox.com/1/oauth2/token \
-d code=<authorization code> \
-d grant_type=authorization_code \
-u <app key>:<app secret>
everything works fine, and I am returned my bearer token. Unfortunately, what
seems to be equivalent code written in node.js with the request module fails.
var request = require("request");
var config = require("./config.json");
request({
url: "https://api.dropboxapi.com/1/oauth2/token",
method: "POST",
auth: {
user: config.client_id,
pass: config.client_secret
},
json: {
code: config.code,
grant_type: "authorization_code"
}
}, function(err, resp, body) {
if (err) throw err;
console.log(body);
});
logs:
{ error_description: 'missing required field "grant_type"',
error: 'invalid_request' }
The docs
say that in the event of a 400 error (which this is), I have:
Bad input parameter. Error message should indicate which one and why.
Though as can be seen from the above code, the grant_type is being
specified.
Notably the docs give a second option to authenticate, though this too fails,
albeit with a different message:
Description (abridged)
Calls to /oauth2/token need to be authenticated using the apps's key and secret. These can either be passed as POST parameters (see parameters below) or via HTTP basic authentication. If basic authentication is used, the app key should be provided as the username, and the app secret should be provided as the password.
Params
code String The code acquired by directing users to /oauth2/authorize?response_type=code.
grant_type String The grant type, which must be authorization_code.
client_id String If credentials are passed in POST parameters, this parameter should be present and should be the app's key (found in the App Console).
client_secret String If credentials are passed in POST parameters, this parameter should be present and should be the app's secret.
redirect_uri String Only used to validate that it matches the original /oauth2/authorize, not used to redirect again.
My attempt at the alternate authentication procedure:
var request = require("request");
var config = require("./config.json");
request({
url: "https://api.dropboxapi.com/1/oauth2/token",
method: "POST",
json: {
code: config.code,
grant_type: "authorization_code",
client_id: config.client_id,
client_secret: config.client_secret
}
}, function(err, resp, body) {
if (err) throw err;
console.log(body);
});
logs:
{ error_description: 'No auth function available for given request',
error: 'invalid_request' }
In case the full response from dropbox for either of my two request attemps would be helpful I posted it on pastebin.
I am not including the redirect_uri as I did not use it as part of the code
flow. This is permitted as per the docs. In any case, I don't have any problems
when ommitting it in the curl command which does succeed.
Considering that my API call succeeds when sent through curl, I'm clearly doing
something wrong with my js request. What can I do to get the bearer token I
expect?
It looks like in your curl command, you're sending a form-encoded POST request (which is what OAuth uses), but in your Node.js code, you're sending a JSON-encoded request.
Try form: { ... } instead of json: { ... }.

Categories