Why is my HTTP DELETE request body showing up as undefined? - node.js

I'm making a webapp where people can review movies, and I'm trying to make it so users can't delete other users' reviews.
Here's my AngularJS function to delete movies:
$scope.del_movie = function(movie) {
$http( {
method: 'DELETE',
url: '/movie/:title',
params: {'title': movie.title},
data: {'username': movie.username}
}).then(function successCallback(response) {
console.log(response);
return getData();
}, function errorCallback(response) {
console.log('Error: ' + response);
});
};
I've console.logged the movie.username and have received the correct username.
However, when this request gets routed to my express delete function, the req.body.username appears to be undefined. Here's that route:
app.delete("/movie/:title", requiresAuth(), function(req, res) {
paramsUsernameString = req.body.username;
oidcEmailString = JSON.stringify(req.oidc.user.email);
console.log("movie " + req.params.title);
if(paramsUsernameString != oidcEmailString){
console.log("req.params.username " + paramsUsernameString + " req.oidc.user.username " + oidcEmailString);
console.log("can't delete someone else's review!");
}
else{
Movie.findOneAndRemove(req.query, function(err, result) {
if ( err ) throw err;
res.json( {
message: "req.params.username " + paramsUsernameString + " req.oidc.user.username " + oidcEmailString,
movie: result
});
});
}
});
I've searched around, and most questions here on SO are resolved by requiring body-parser, but I've already done that:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
My POST request also uses body-parser, and that one works fine.
Appreciate any help with this, happy to provide more information if needed. Thanks!

The problem is not exactly in your code as it is in the AngularJs $http service. Link to original answer
Sending a body in an HTTP DELETE is discouraged by some providers, but the HTTP spec does not explicitly prohibit it. That's why we end up with these kinds of situations
What you should do in order to overcome this is to explicitly add a Content-Type: application/json header and force the HTTP client, or, better yet, don't send a body in a DELETE request as it is not recommended.
Instead of using the body, you should consider using path params, query params, or maybe even a user header since it seems that is what you are trying to pass in the request
Also make sure you actually use body-parser and not just require it
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json())

Related

How to fix, "{ error: { status: 400, message: 'Bad search type field tracks' } }" occurred while using Spotify Search API

Back-end on: node.js, express. Other modules used: body-parser, request.
I am trying to fetch track ID from Spotify Search API.
A user makes a POST request. The request is fed to the server.
The server makes GET request to the endpoint.
The endpoint returns data.
The data is parsed to JSON.
Problem: Upon parsing, following error is logged into the terminal.
{ error: { status: 400, message: 'Bad search type field tracks' } }
Code to focus on:
request({
url: searchUrl,
headers: {
"Authorization": token
}
}, function(err, res) {
if (res) {
var data = JSON.parse(res.body);
// var spotifyTrackIdAppJs00 = data.tracks.items[0].id;
console.log(data);
// console.log(trackId);
}
)
Complete app.js code:
// It is a nodejs, expressjs project.
const express = require("express");
// 'body-parser' is used to access tags from the html file. We'll be using it to access queryValue.
const bodyParser = require("body-parser");
// request package; to fetch data from search endpoint.
const request = require("request");
// This app constant is created to be able to access the menthods available in 'express' package.
const app = express();
// 'urlencoded' helps access html data. Other data formats could JSON etc.
// body-parser required as to exclusively define "extended: true" although this is no use to us.
app.use(bodyParser.urlencoded({
extended: true
}));
// This sets a static directory to look for source files like css, js, img. These file links are mentioned in html or ejs files.
// A folder named 'public' has to be in the same directory as "app.js". The source files are stored here.
app.use(express.static("public"));
// ejs view engine has been used to use app.js variables into the output ejs file.
app.set('view engine', 'ejs');
// Variable(s) to store the data fetched from API endpoint.
var data = "";
// The page to load when the browser (client) makes request to GET something from the server on "/", i.e., from the homepage.
// This GET request is made as soon as the homepage url is entered in the address bar od browser, automatically.
app.get("/", function(req, res) {
res.sendFile(__dirname + "/index.html");
});
// The data that server should POST when the POST request is sent by the client, upon entering the search queryValue, in the search bar (form).
app.post("/", function(req, res) {
// The user input query. We are using body-parser package here.
const query = req.body.queryValue;
// Follow procedure here to get access_token and refresh_token: https://benwiz.com/blog/create-spotify-refresh-token/
const access_token = {access_token};
const token = "Bearer " + access_token;
var searchUrl = "https://api.spotify.com/v1/search?q=" + query + "&type=tracks&limit=4";
request({
url: searchUrl,
headers: {
"Authorization": token
}
}, function(err, res) {
if (res) {
var data = JSON.parse(res.body);
// var spotifyTrackIdAppJs00 = data.tracks.items[0].id;
console.log(data);
// console.log(trackId);
}
// res.render("results", {
// spotifyTrackIdEjs00: spotifyTrackIdAppJs00
// });
// console.log("Value to be used in rendered file: " + spotifyTrackIdAppJs00);
})
});
// Starting the server. Should this be placed at the top of all other commands?
app.listen(3000, function() {
console.log("Server is running on port 3000.")
});
Helpful Resources:
Follow the steps here to get the access_token: https://benwiz.com/blog/create-spotify-refresh-token/
Understand parameters here: https://developer.spotify.com/documentation/web-api/reference/#category-search
Spotify Web Console to understand the JSON arrangement: https://developer.spotify.com/console/get-search-item/
I am an absolute beginner. Please teach me like I'm five. I would be highly grateful to you.
Your code looks fine, but you have one typo that is messing up all. This one:
var searchUrl = "https://api.spotify.com/v1/search?q=" + query + "&type=tracks&limit=4";
The Spotify's API's parameter type have the following valid valued:
album , artist, playlist, track, show and episode.
On your searchUrl, you are using tracks (plural) instead of track, so it should be:
var searchUrl = "https://api.spotify.com/v1/search?q=" + query + "&type=track&limit=4";
For the future: the HTTP's 400 code means "Bad Request", meaning that server is telling you that something is being sent wrong on the request. When you get that kind of error response, usually is good to double check the required params/body of the API you are consuming and their accepted values

NodeJS http post data empty

I am not able to get the data in the http post method of express nodejs.I am posting data from angular2. When i inspect in the network section of chrome, the payload is visible but the same data is received blank at app.post method.Please help me.
angular2 code
this.headers = new Headers();
this.headers.append('Content-Type', 'x-www-form-urlencoded');
let body = JSON.stringify({name:"Lionel Messi"});
return this.http
.post('http://localhost:8081/save',body
,this.headers);
}
nodejs code
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/save', function (req, res) {
console.log("Got a POST request for the homepage");
console.log(req.body);// output - {}
res.send('Hello POST');
})
Network Section in Chrome....payload is proper
alert method in node.js will not work . You need to use console.log("Hello");
Second thing is to get body data , use req.body.name
My way of writing code is like below and it works
$http({
method: 'POST',
url: 'http://localhost:8081/save',
data: {name:"Lionel Messi"}
})
.success(function(data) {
return data
})
.error(function(error) {
// handle error
});
Other way you can try is:
$http.post('http://localhost:8081/save', {name:"Lionel Messi"})
.then(function(data) {return data})
.catch(function() {console.log("Error Occured");});
You can do it like this-
Suppose you have sent username and password from your browser by post method.
app.post("/ url,function(request,response)
{ var username=request.body.username;
var password=request.body.password;})

Avoid global variables in Node, how to return the body of a request from a POST call

I'm still new to Node so I'm sure I'm doing something wrong, but some searching isn't helping so here we are.
I'm making a request to an API to get weather data. I can get the data and log it to the console no problem, but I'm having trouble getting the body of the request to end up in the response to the original POST.
var express = require('express');
var request = require('request');
var bodyParser = require('body-parser');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// make the web server use body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
console.log("server starting on " + appEnv.url);
});
// Send information from the weather API to the console
app.post('/processWeather', function (req, res) {
requestString = 'http://api.openweathermap.org/data/2.5/weather?id=7839805&appid=xxxxxxxx';
request(requestString, function(err, res, body){
if (!err && res.statusCode == 200) {
console.log(body);
}
});
//redirect back to homepage after getting the weather
res.redirect("/");
});
So the problem with this is that I can't simply use the body variable in the app.post callback. I'm suspicious this is to do asynchronous logic but I'm as I'm new I can't wrap my head around the best way to do this without using a global variable to temporarily store the body variable. How can I get the contents of the body variable sent back to the browser? Any help greatly appreciated. Cheers.
Don't use global variables unless it's absolutely necessary!
You can use session.
req.session['weather'] = weatherData; // Weather data
res.redirect("/");
You can use a lot of other ways also. But this is what I'd prefer.
I figured out what I needed. All I had to do was place the request in the res.send
res.send(request(requestString));

node js POST not getting data using React

I am submitting a form and the following gets called...
handleLogin(){
fetch('http://localhost:8080', {
method: 'post',
body: JSON.stringify({
username: this.state.username,
password: this.state.password
})
});
}
It makes a POST request to my restAPI. The request works, but the data is not passed...
app.post('/', function(req, res, next) {
console.log(req.body.username);
....
This prints out undefined, meaning password and username are not passed through the call. What am I doing wrong?
Express by default doesn't parse the body of the request. In order to enable parsing, you will need to use a middleware such as body-parser. You can find some information in the express docs.
Also, the client side needs to indicate that it's sending json data. That can be achieved with the Content-Type header. There is a pretty good tutorial about fetch() here. You can jump directly to the Request Headers section which is relevant for your question.
var express = require("express");
var app = express();
var bodyParser = require('body-parser');
const PORT = process.env.PORT || 7070;
const BASEURL = process.env.BASEURL || 'http://localhost/7070';
app.use(bodyParser.urlencoded({extended:true}));
app.listen(PORT, function() { console.log('Server running on'+BASEURL);
});

How can I use "express-http-proxy" after bodyParser.json() has been called?

I am building a cross system admin app, which will be used as an admin tool for multiple backend systems. The app is built on top of Mean.js.
I have setup a /proxy route using "express-http-proxy" to send all sub-routes to their respective backend system endpoints. However, I need to have each request authenticated within my admin app and then decorated with the targeted backendSystem credentials before the "express-http-proxy" can continue. Here's an example of my /proxy route...
app.use('/proxy', users.requiresLogin, expressHttpProxy(config.backendSystem.host, {
forwardPath: function (req) {
return '/1.0' + require('url').parse(req.url).path;
},
decorateRequest: function (req) {
req.headers['content-type'] = 'application/json';
req.headers['backend-system-id'] = config.backendSystem.id;
req.headers['backend-system-key'] = config.backendSystem.key;
return req;
}
}));
NOTE:
Currently the backendSystem credentials are stored based on the environment my admin app is ran in. However, in the future the backendSystem credentials will be specified by the user, and this /proxy route will differently than what is currently shown.
THE ISSUE:
Proxy routes that require data within the request body don't work.
e.g. POST /comments {"user": user_id, "text": "rabble rabble rabble"}
WHAT I'VE FOUND:
bodyParser.json() and "express-https-proxy" don't play nice. I've confirmed this by removing bodyParser.json() from express.js.
However, this isn't a full solution since almost all of my other routes need bodyParser.json, e.g. /auth/signin.
Does anyone have a clean way that I can make a route exception for my /proxy route so that bodyParser.json won't be called for it?
As far as I understand, the root of problem is so:
if you were reading a POST request by pure node, you should be using a code like this
if (req.method == 'POST') {
console.log("POST");
var body = '';
req.on('data', function (data) {
body += data;
console.log("Partial body: " + body);
});
req.on('end', function () {
console.log("Body: " + body);
});
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('post received');
}
in other words, you need to use the req.on('data') & req.on('end') events.
but the problem is,that you can use this code only once. after the 'end' is called, the request is consumed.
so then you use bodyParser , it consumes the request, and the proxy have nothing to do with it.
actually, in my opinion, the proxy wait for the 'data' event to appear , but it will newer happen, so the code halts.
The solution:
you need to 're-enable' the events. I used this code and it works for me.
var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');
//call for proxy package
var devRest = require('dev-rest-proxy');
//init express (as default)
var users = require('./routes/users');
var app = express();
app.use(bodyParser.json());
//set the proxy listening port
app.set('port', 8080);
//process the POST request
app.post('/users/*', function(req, res) {
//just print the body. do some logic with it
console.log("req.body: ",req.body);
//remove listeners set by bodyParser
req.removeAllListeners('data');
req.removeAllListeners('end');
//add new listeners for the proxy to use
process.nextTick(function () {
if(req.body) {
req.emit('data', JSON.stringify(req.body));
}
req.emit('end');
});
//forward the request to another server
devRest.proxy(req,res, 'localhost', 3000);
});
//start the proxy server
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
module.exports = app;
the solution found on schumacher-m post (github of nodejitsu)
I was able to resolve my issue by adding a regex that excluded my /proxy route to where bodyParser.json was being added within express.js. I found that from this answer
While this approach doesn't scale well, it solved my immediate issue.
I get it works by converting the data into query string using 3rd party query-string as follows:
proxyReqBodyDecorator: function(bodyContent, srcReq) {
return (queryString.stringify(bodyContent));
}
Have tried JSON.stringify but not working, need the data in the following format
array_field=val1&array_field=val2&array_field=val3......
To modify the request body, do this with the latest express-http-proxy v1.6.2:
const express = require('express');
const proxy = require('express-http-proxy');
const bodyParser = require('body-parser');
const conf = {
proxyHost: 'some.example.net:9200',
proxyOptions: {
proxyReqBodyDecorator: modifyRequestBody,
preserveHostHdr: true,
parseReqBody: true
},
port: 8073
};
var app = express();
app.use('/proxy', proxy(conf.proxyHost, conf.proxyOptions));
function modifyRequestBody(body, srcReq) {
if(srcReq.method.match(/^(GET|POST)$/i)) {
try {
// convert buffer to string, then to object
var str = Buffer.from(body).toString('utf-8');
var reqBody = JSON.parse(str);
if(someCondition)) {
reqBody.addStuff = 'whatever';
body = reqBody; // return modified body as object
}
} catch(error) {
console.log('- error: ' + JSON.stringify(error));
}
}
return body; // return original buffer, or modified object
}
app.listen(conf.port, function () {
log('app listening on port ' + conf.port);
});
You can fill the proxyReq.bodyContent inside the decorateRequest method with the JSON-ed data from originalReq.body to be correctly POST'ed:
app.use('/proxy', users.requiresLogin, expressHttpProxy(config.backendSystem.host, {
...
...
decorateRequest: function (proxyReq, originalReq) {
...
...
if (originalReq.body) {
proxyReq.bodyContent = JSON.stringify(originalReq.body);
}
return proxyReq;
}
...
...
}));

Resources