Mailgun webhook POST body seems empty - node.js

I'am trying to handle http post message from Mailgun bounce webhook. When sending it to Mailgun's Postbin service all data is found of course. But I'm now sending that POST to my localhost server for development purposes and all I get is empty json array. I use Test Webhook.
Intent is to keep this simple as possible besides our main service. That for I started using nodejs/expressjs to create stand alone webservice to work as relay to receive POST messages of email bounces from Mailgun and inform admins about bounced email addresses.
Now I can't figure why I don't get the same data as is visible in Postbin.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mailgun = require('mailgun-js')({apiKey: 'key-...', domain: 'mymailgundomain.com'});
app.use(bodyParser.urlencoded({
extended: true
}));
function router(app) {
app.post('/webhooks/*', function (req, res, next) {
var body = req.body;
if (!mailgun.validateWebhook(body.timestamp, body.token, body.signature)) {
console.error('Request came, but not from Mailgun');
res.send({ error: { message: 'Invalid signature. Are you even Mailgun?' } });
return;
}
next();
});
app.post('/webhooks/mailgun/', function (req, res) {
// actually handle request here
console.log("got post message");
res.send("ok 200");
});
}
app.listen(5000, function(){
router(app);
console.log("listening post in port 5000");
});
I'm running this from Mailgun's Test Webhook using url like http://mylocalhostwithpublicip.com:5000/webhooks/mailgun
Code structure is copied from https://github.com/1lobby/mailgun-js. Probably I'm missing something fundamental here as I can't figure it out myself.

The reason you're not seeing req.body populated is because the body-parser module does not support multipart/form-data requests. For those kinds of requests you need a different module such as multer, busboy/connect-busboy, multiparty, or formidable.

If your content-type (shown by logging console.dir(req.headers['content-type'])) is 'application/x-www-form-urlencoded', and you're using body-parser, try adding the following line:
bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))

to make it work with multer, you can use .any() (version 1.1.0)
for me it worked like this: (assuming multer is included and declared as "multer")
post('/track', multer.any(),function(req, res){
//if body is a string, parse the json
var data=(typeof req.body=='string')?JSON.parse(req.body):req.body;
//if data is an object but you can't verify if a field exists with hasOwnProperty, force conversion with JSON
if(typeof data=='object' && typeof data.hasOwnProperty=='undefined')
data=JSON.parse(JSON.stringify(data));
//data is your object
});

var multer = require('multer');
var msg = multer();
post('/track', msg.any(), function(req, res){
console.log(req.body);
}

I make a custom parser for get data in req.body when the Content-type = 'multipart/alternative'
https://github.com/josemadev/Multiparser/

Related

Body-parser fails to/do not parse urlencoded parameters from GET request

I'm creating a web platform with a Nodejs server. I'm trying to retrieve urlencoded data sent from my front but can't manage to.
How I send the GET request :
xhr.open("GET", address + "?limit=1&offset=1",true);
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(null);
xhr.addEventListener("readystatechange", processRequest, false);
On the server side :
const bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: true });
app.get('/guid_list', urlencodedParser, function (req, res) {
console.log(req.body.limit);
console.log(req.body.offset);
var headerjwt = HeaderGetJWT(req);
...
}
I have no problem retrieving the jwt token I'm sending, but always get undefined for urlencoded parameters.
I was wondering if I should use multipart content type instead, since I'm sending both a token and urlencoded data ? And maybe "multer" module in that case, since body-Parser does not support that content type.
I would suggest accessing your parameters in Node.js as follows (since they are being passed as query parameters):
app.get('/guid_list', parser, function (req, res) {
console.log("req.query.limit:", req.query.limit);
console.log("req.query.offset:", req.query.offset);
});
or just log all parameters:
app.get('/guid_list', parser, function (req, res) {
console.log("req.query:", req.query);
});

Postman send strange response for raw JSON post (node js)

I'm trying to do a POST request using raw json.
In the Body tab I have "raw" selected with this body:
{
"name": "book"
}
On the Node js side I'm doing res.send(JSON.stringify(req.body))
router.post('/', (req, res, next) => {
res.send(JSON.stringify(req.body));
}
And in POSTMAN response I receive:
{"{\n\"name\": \"book\"\n}":""}
When expected something like
{"name":"book"}
Have no idea - where could be a reason for it?
You'll need to use the Express JSON body parser, install using
npm install body-parser;
Then:
const bodyParser = require('body-parser');
app.use(bodyParser.json());
Once you do this, the JSON data will be parsed correctly and when you send it back it will render correctly.
Also make sure you have your Content-Type header set to "application/json" in your Postman request (go to "Headers" and add a new "Content-Type" header with value "application/json")
Here's a simple express app that will echo any JSON POST:
const express = require("express");
const port = 3000;
const app = express();
const bodyParser = require('body-parser')
app.use(bodyParser.json());
app.post('/', (req, res, next) => {
console.log("Body: ", req.body);
res.send(JSON.stringify(req.body));
})
app.listen(port);
console.log(`Serving at http://localhost:${port}`);
If you're on Express v4.16.0 onwards, try to add this line before app.listen():
app.use(express.json());
This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.
Looks to me like its not a fault of Postman, but your NodeJS service is applying JSON.stringify twice?
Can you log the response type from the server to console to check whether its already json content or not?
try with hard coded json response and then with dynamic variable
res.json({"name":"book"});

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.

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));

Using multiple parameters in URL, params between static url are not available

I am using express.js (v 4.13.4), node.js (v 0.12.5) and body-parser (v 1.13.2) to create a simple chat RESTful API.
I have this url path which must be called by the user:
http://myhost/chat/room/:roomId/message/:messageId
Body-parser is set like this:
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
I am unable to read the first url parameter :roomId but the :messageId is available.
I am accessing those parameters using req.params.roomId and req.params.messageId in request callback function.
Question:
Is it wrong to have parameters in the middle of a url?
Why would the application not parse :roomId?
The parameters roomId and so are send as query parameter therefore req.params.roomId is required to fetch.
Another way to do is send params as body, that way URL will be clean and then to access params body-parser is required.
To send params in body, create a post request through postman and specify params there.refer this for sending params in body
It is working in my case.
var app = require('express')();
var bodyParser= require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/chat/room/:roomId/message/:messageId', function(req, res){
console.log('Room Id: '+req.params.roomId);
console.log('Message Id: '+req.params.messageId);
res.sendStatus(200);
});
app.listen(3000);
Now, if I try to access localhost:3000/chat/room/1/message/100, I get
Room Id: 1
Message Id: 100
Please check the spelling of roomId. May be typo can be the issue.
Thank you for your answers Mukesh Sharma and Himani Agrawal.
I found the issue now, here it is:
If I register a room router like this:
var RoomRouter = express.Router();
RoomRouter.get('/:roomId/message/:messageId', function(req, res) {
console.log('Room Id: '+req.params.roomId);
console.log('Message Id: '+req.params.messageId);
res.status(200);
res.send("Ok");
});
app.use('/chat/room', RoomRouter);
:roomId and :messageId are received accordingly.
But if I register the room router like this (as it was when I posted the error) :roomId is not available.
var RoomRouter = express.Router();
RoomRouter.get('/message/:messageId', function(req, res) {
console.log('Room Id: '+req.params.roomId);
console.log('Message Id: '+req.params.messageId);
res.status(200);
res.send("Ok");
});
app.use('/chat/room/:roomId', RoomRouter);
This was my issue, I don't know exactly why the url would be parsed differently in two different situation but I am sure this has a logic somewhere.

Resources