empty body on resource.$save - node.js

So I've tried the suggestions from
AngularJS POSTs empty requests?
AngularJS $resource RESTful example
Send Request Body on $resource
But I'm still getting an empty req.body
I can do a get just fine and even pass an id for the get. But I can't seem to POST and transfer the data to the server.
Controller:
.controller("createEventController", ["$scope", 'CreateEventService', '$location', function($scope, CreateEventService, $location){
$scope.event = {};
$scope.submitEvent = function(){
console.log($scope.event);
var events = new CreateEventService($scope.event);
console.log(events);
events.save(function(response){
console.log(response);
}, function(error){
console.log(error);
});
}
}])
Service
factory('CreateEventService', function($resource){
return $resource('api/createEvent');
});

Change events.save(...) to events.$save(...)

You should use bodyParser.json(). The $resource, by default sends his requests with the header "Content-Type": "application/json;charset=UTF-8" and without bodyParser.json() you're API is not able to deal with the request content.

if using express 4.1.2, despite it fussing about bodyParser() being deprecated, having
app.use(bodyParser.urlencoded({
extended: true
}));
was for some reason, giving me an empty body. For whatever reason, not having urlencoded crashed my server before (old express version I think). Just change it back to (using express 4.1.2)
app.use(bodyParser());
and fixed. I also removed the methodOverride() as that was causing my server to hang. If anyone knows a more correct approach, I would appreciate it.

Related

How to set CSURF (Express Middleware) up to work with Postman?

How do you you set up a working server to test CSURF in Postman, as per the CSURF documentation:
http://expressjs.com/en/resources/middleware/csurf.html
Thanks for your question and answer, it helped solve part of the puzzle setting up Postman. I'm posting my own answer for a bit of clarity on a couple of points, with the bonus of automating copying the token into Postman requests
1. Cookie parser comes first
app.use(cookieParser())
2. Send _csrf cookie
app.use(csrf({ cookie: { httpOnly: true, }}))
This returns Cookie 1: _csrf.
Using httpOnly is recommended because it keeps the cookie out of the reach of JavaScript and is more secure
3. Send XSRF-Token cookie
Sets a second cookie that needs to be returned with each request
app.use((req, res, next) => {
res.cookie('XSRF-TOKEN', req.csrfToken())
next()
})
4. Return XRSF-Token* header
This needs to be on every request (all that use POST, DELETE, etc) and is different after every call
There are alternatives to using a header (a body property or query can be used instead) but using a header seems cleaner, especially when using JSON
a. Set up and send a GET request on Postman (Since get requests don't check for csrf by default)
b. Set up a POST request in Postman, set this header, using the cookie value from the GET request
XSRF-Token abc123...
*Note the hyphen (-), not underscore (_)
4. Automatically set header in Postman
Postman automatically keeps and sends cookies, like a browser, but we need some way to obtain the token from the last request and copy it into our next request
Tests in Postman run a snippet of Javascript after each request and will work well for this purpose
I set this test up on one of my GET requests, so I'm sure it won't be invalid on the first request
// A Postman Test script
const xsrf_token = postman.getResponseCookie('XSRF-Token')
postman.setEnvironmentVariable('xsrf_token', xsrf_token.value)
Then, in your POST request's headers, switch out the copy pasted string for the environment variable
XSRF-Token {{xsrf_token}}
Now you should be right to POST to your heart's content in Postman
I've had to relearn this a couple of times so I thought it'd be handy for everyone to see the breakdown:
In your server:
In index.js:
const app = require('./app')
app.set('port', 5000);
app.listen(app.get('port'), () => {
console.log('App running on port', app.get('port'));
});
In app.js:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
// pass the csrfToken to the view
// res.render('send', { csrfToken: req.csrfToken() })
res.send({csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
module.exports = app;
Start your server
In Postman:
GET Request:
Send a GET request to http://localhost:5000/form
Hit 'Send'. Below the request info you should see the following in the response data:
Copy the string between the quotation marks. (In this example: H3DsAwqv-FuM06caBMOh6QZRFaILYgFyqFlA )
POST Request:
Set up a POST request to http://localhost:5000/process
Click the 'Body' tab and select the radio button for 'x-www-form-urlencoded'.
Enter a new key "_csurf" and paste the string value we received in the GET request.
Your POST request should now look like this set up:
Hit 'Send'. You should now see this information:
If you see 'data is being processed' then you know it's working!
I made a YouTube tutorial in case this makes things easier:
https://youtu.be/QruvuwM-kkU

JSON comes in undefined, where is the data lost?

I am using postman to test a rest API I'm building for a project. I'm trying to send some data to a post method, but the data is getting lost somewhere between Postman and the endpoint.
I've tried tracing the data with console logs, but nothing comes out (req.body is undefined). I'm pretty sure the issue isn't with the endpoint or router, as the same error comes up in postman as in the console of my IDE, which means there's some sort of communication.
// json I'm putting into postman. validated with Jsonlint.com
{
"Name": "testN",
"file": "file1",
"Path": "/home/userf",
"userName": "user1"
}
// profileWrite.js
const dbProfileWrite = require('../...db-ProfileWrite');
const bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
// my post method
async function post(req, res, next) {
try {
console.log("attempting to parse data: " + req.body);
let profile = req.body;
console.log("data parsed, writing profiles");
profile= await dbProfileWrite.writeProfile(profile);
res.status(201).json(profile);
} catch (err) {
next(err);
}
}
module.exports.post = post;
UPDATE 7/15/19:I have recreated a microversion of my project that is having this issue on stackblitz. there's some sort of package error that I'm working on, but here's the link. I've recreated the methodology I'm using in my project with the router and all and looked at the example in the express docs. hopefully this helps isolate the issue.The data still comes in undefined when I post to this api through postman, so helpfully this much smaller view of the whole project helps.
Assuming you are using Express framework, by the look of the post function. You need to use a middlewear function to process request body using body-parser. Make sure you are using the correct parser in this case
app.use(bodyParser.json())
You don't need body-parser anymore it was put back in to the core of express in the form of express.json, simply use app.use(express.json()).
To access the body of your request use req.body, it should come with a object with the keys representing the json sent;
var app = express();
app.use(express.json());
async function post(req, res, next) {
try {
console.log("attempting to parse data: " + req.body);
let profile = req.body; // no need to use any functions to parse it
console.log("data parsed, writing profiles");
profile= await dbProfileWrite.writeProfile(profile);
res.status(201).json(profile);
console.log("profilecreated");
} catch (err) {
next(err);
}
}
See the express documentation
Solved the issue myself with a little help from John Schmitz. The issue was that I was defining the router and the server before actually telling it how to handle json bodies/ objects, so the body came through as the default undefined. In my index.js, the following is what fixed the code:
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use('/api/v1', router);
the key to this is that the app is told to use json and express.urlencoded before the router is declared. these actions have to happen in this order, and all before app.listen is called. once the app is listening, all of its params are set and you can't change them. Tl;dr: node is VERY picky, and you HAVE to define these things in the right place. thanks all for the help.

ajax call cant pass parameter to nodejs app

I make a ajax call via code below and expect to see parameters passed nodejs app, but it always empty
#action postData() {
$.ajax({
url:"http://localhost:8080/sendMail",
ContentType:'application/json',
dataType:'json',
type:'post',
data:JSON.stringify({'message':'helloworld'}),
success:(result) =>{
..
})
If I make a post request within postman(adding raw string json parameters to body; {'message':'helloworld'}) its passed well and I see its logged. So whats wrong with this ajax call that i used in reactjsapp ?
Edited: it looks all parameters passed in browser fine but somehow nodejs unable to get them..
Since POST data is sent in the HTTP body, you need to parse the JSON in there to get it. Assumed you use express.js on the server side, you could use body-parser to do that:
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())

Cross-domain POST request in Node.JS with preflight?

I have just started with Node.
I am trying to get cross-domain form data from an HTML form to parse in a Node.js server. I have been able to do this with simple POST data, not with POST requests that require preflight.
I am running the Node code on cloud9 app servers. I am also using the Cors module to handle the requests. This module works well with simple requests (test here to see a simple request work), however with requests that require preflight I get this result from the Chrome inspector console.
XMLHttpRequest cannot load https://nms-motaheri-1.c9.io:8080/mail.
The request was redirected to 'https://c9.io:8080/api/nc/auth?.....SHORTENED',
which is disallowed for cross-origin requests that require preflight.
Here is my server.js code:
// Define dependencies
var express = require('express')
, cors = require('cors')
, app = express()
, parse_post = require("parse-post");
// Core module config
var corsOptions = {
origin: '*',
preflightContinue: true // <- I am assuming this is correct
};
app.use(cors(corsOptions));
// Respond to option request with HTTP 200
// ?? Why is this not answering my OPTION requests sufficiently ??
app.options('*',function(req,res){
res.send(200);
});
// Give a hello world response to all GET requests
app.get('/',function(req,res){
res.sendFile(__dirname + '/index.html');
});
// Handle all POST requests to /mail
app.post('/mail', parse_post(function(req, res) {
console.log(req.body);
res.json({msg: 'This is CORS-enabled for all origins!'});
})
);
// Listen on default Cloud9 port which is 8080 in this case
app.listen(process.env.PORT, function(){
console.log('CORS-enabled web server listening on port ' + process.env.PORT);
});
Why is this happening and how can I satisfactorily answer the OPTION request for my POST with pre-flight?
Here is the post request and response in Chrome dev tools:
Turns out that part of the problem was that the cloud9 server was set to private making these requests all redirect.
After making the server public, the redirections stopped. However, I received an error that the Node.js server did not have any Access-Control-Allow-Origin headers to allow requests from my cross origin domain. I noticed that "simple" with-out preflight requests would go through. So instead of trying to understand why it was not accepting my allow-all-origin-configuration on the Node.js side I decided to serialized the POST data to get rid of the preflight requirement and changed the data type in my angular request to plain text.
To get rid of preflight, first get rid of any POST header configuration (cache, etc), make sure your request Content-Type is plain text and make sure your actual content is plain text too. So if it is in JSON serialize it in jQuery before sending it with POST.
This is what my new Angular Post request code looked like:
sendEmail: function(email) {
var config = {
headers: {
'Content-Type': 'text/plain'
}
};
var POSTDATA= JSON.stringify(POSTDATAJSON);
return $http.post(POSTURL, POSTDATA, config)
}
And in Node.js this, I am using the cors Node.js module:
app.post('/mail', parse_post(function(req, res) {
var postReq = JSON.parse(Object.keys(req.body));
}));

Nodejs: How can i simply get the request body using express4?

Now that express is not shipped anymore with middleware that fills the req.body variable i am fighting to get req.body filled again.
I am sending a POST request to /xyz/:object/feedback.
here my code:
app.post('/xyz/:object/feedback', function(req, res)
{
console.log('Feedback received.');
console.log('Body: ', req.body); // is not available :(
res.set('Content-Type', 'text/plain; charset=utf8');
res.send(result ? JSON.stringify(req.body) : err);
});
I tried to use body-parser already, but "Feedback received." never got logged to my console. So something seems to get stuck here:
var bodyParser = require('body-parser');
app.use(bodyParser);
How can i get req.body filled? (i need some working code)
The problem is that you pass the whole module to the use method not the required instance.
Instead of this:
app.use(bodyParser);
do
app.use(bodyParser());
You need to do app.use(bodyParser()).
bodyParser() will return a function with what to use. bodyParser on its own is an invalid function for Express.

Resources