Req.body of a twilio webhook request is undefined node js - node.js

I tried following this twilio article:
https://www.twilio.com/blog/parsing-an-incoming-twilio-sms-webhook-with-node-js
The following is my server in its entirety
// Imports
const http = require('http')
const express = require('express')
const app = express()
const port = 80
const MessagingResponse = require('twilio').twiml.MessagingResponse;
// Static Files
app.use(express.static('public'))
// Set views
app.set('views', './views')
app.post('/sms', (req, res) => {
const twiml = new MessagingResponse();
// Access the message body and the number it was sent from.
console.log(req.IncomingMessage.body)
res.writeHead(200, {'Content-Type': 'text/xml'});
res.end(twiml.toString());
});
// Listen on port
app.listen(port, () => {
console.log(`Running on port ${port}`)
})
I have the webhook of my twilio phone posting to "http://{domain}.com/sms"
Every time I send a text to my twilio phone, I get the following error:
TypeError: Cannot read property 'body' of undefined
at app.post (/home/ubuntu/{domain}/server.js:24:37)
at Layer.handle [as handle_request] (/home/ubuntu/{domain}/node_modules/express/lib/router/layer.js:95:5)
at next (/home/ubuntu/{domain}/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/ubuntu/{domain}/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/ubuntu/{domain}/node_modules/express/lib/router/layer.js:95:5)
at /home/ubuntu/{domain/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/home/ubuntu/{domain}/node_modules/express/lib/router/index.js:335:12)
at next (/home/ubuntu/{domain}/node_modules/express/lib/router/index.js:275:10)
at serveStatic (/home/ubuntu/{domain}/node_modules/serve-static/index.js:75:16)
at Layer.handle [as handle_request] (/home/ubuntu/{domain}/node_modules/express/lib/router/layer.js:95:5)

I don't think the req object has any property called IncomingMessage. Instead you could try:
console.log(`Incoming message from ${req.body.From}: ${req.body.Body}`);
So based on the twilio specs, the endpoint would look like:
app.post('/sms', (req, res) => {
const twiml = new MessagingResponse();
// Access the message body and the number it was sent from.
console.log(`Incoming message from ${req.body.From}: ${req.body.Body}`);
res.writeHead(200, {'Content-Type': 'text/xml'});
res.end(twiml.toString());
});
Since the message body is in the req.body.Body parameter, so console logging this property will show you the message text.

First answer is correct,
console.log(`Incoming message from ${req.body.From}: ${req.body.Body}`);
but I had to make sure to set the express urlencoding or else req.body came back as undefined.
app.use(
express.urlencoded({
extended: true,
})
);

I'm not sure if this is correct but when I'm using express I use req.body.IncomingMessage
console.log(req.body.IncomingMessage)

Related

API receiving undefined data

I'm new to JS and react, but I'm attempting to pass a string to my API which will then run analysis on said string and pass back a sentiment score. However when I pass the data, whilst in my API's console the string appears in the 'body', the API states that the 'Description' is undefined, causing the API to throw an error.
api.js
const express = require('express');
const app = express()
app.use(express.json());
app.post('/', function (req, res) {
console.log('body is:', req.body);
const {description} = req.body;
console.log('Description is:', description);
var Analyzer = require('natural').SentimentAnalyzer;
var stemmer = require('natural').PorterStemmer;
var analyzer = new Analyzer("English", stemmer, "afinn");
const sentiment = analyzer.getSentiment(description.split(' '));
console.log('Sentiment is:', sentiment);
res.json(JSON.stringify({sentiment}))
})
app.listen(3000, () => {
console.log('listening on port 3000');
});
diary.js containing the post function and the api call
async function makePostRequest (diaryText) {
let payload = { Description: diaryText };
let res = await axios.post('http://localhost:3000/', payload);
let data = res.data;
console.log("This is the data returned in the post function:",data);
}
makePostRequest("testText").then(response => {
console.log("Data returned from the function call:", response);
}).then(error => {
console.error(error.response.data);
});
This is the output in the console when the above code is executed:
body is: { Description: 'testText' }
Description is: undefined
TypeError: Cannot read property 'split' of undefined
at /Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/api.js:14:54
at Layer.handle [as handle_request] (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/layer.js:95:5)
at /Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/index.js:335:12)
at next (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/express/lib/router/index.js:275:10)
at /Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/body-parser/lib/read.js:130:5
at invokeCallback (/Users/ddavies/Desktop/Desktop Storage/programming/MSc_App/node_modules/raw-body/index.js:224:16)
Object key is sensitive, Description =/= description
const {Description} = req.body;

Cant use parseInt() in LocalHost NodeJS - Body Parser

im actully new in node js so i got this error while using parseInt or Number() in my server
code :
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/bmicalculator", function(req, res) {
res.sendfile(__dirname + "/index.html");
});
app.post("/bmicalculator", function(req, res) {
var nm1 = parseInt(req.body.num1); // <-- here the error
var nm2 = parseInt(req.body.num2); // <-- here the error
var result = nm1 + nm2 * nm2;
res.send(result);
});
app.listen(3000, function() {
console.log("server started");
});
here the error from Browser & Terminal :
RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: 29636
at ServerResponse.writeHead (_http_server.js:248:11)
at ServerResponse._implicitHeader (_http_server.js:239:8)
at ServerResponse.end (_http_outgoing.js:763:10)
at ServerResponse.send (C:\Users\Amir\Desktop\Calculator\node_modules\express\lib\response.js:221:10)
at C:\Users\Amir\Desktop\Calculator\calculator.js:16:9
at Layer.handle [as handle_request] (C:\Users\Amir\Desktop\Calculator\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Amir\Desktop\Calculator\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\Amir\Desktop\Calculator\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\Amir\Desktop\Calculator\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\Amir\Desktop\Calculator\node_modules\express\lib\router\index.js:281:22
This error seems to be caused by the method res.send. In old version of Express (v3),
the first argument used to be http status code but in your case, it's a big number (invalid http status code), hence the error is thrown.
in order to fix this, you can do either
upgrade to a newer version of express.
do this res.send(200, result) instead.
See the Express v3 docs here for reference: https://expressjs.com/en/3x/api.html#res.send
res.send([body|status], [body])
Send a response.
res.send(Buffer.from('whoop'))
res.send({ some: 'json' })
res.send('<p>some html</p>')
res.send(404, 'Sorry, we cannot find that!')
res.send(500, { error: 'something blew up' })
res.send(200)
You can see your case is same as the last example but your first argument is a big number 29636, which is invalid status code.
Add:
app.use(bodyParser.json());
And change the reponse to:
res.send(200, result);

nodejs trying to get remote file to open to user

Wondering what I am doing wrong here. All i want is for the mp3 which I have wired in to be downloaded to the user.
My ideal solution would be able to add a mp3 to the front of this.
const express = require('express');
var fs = require('fs');
request = require('request');
const http = require("http");
const https = require("https");
router.get('/a/:url(*)', (req, res) =>{
res.set({
"Content-Type": "audio/mp3",
// 'Transfer-Encoding': 'chunk',
// 'Content-Disposition': 'attachment'
});
const file = fs.createWriteStream("audio.mp3");
var url = req.params.url.substr(0);
console.log(url);
https.get('https://storage.googleapis.com/ad-system/testfolder/OUTOFAREA.mp3', response => {
response.pipe(file);
});
https.get(url, response => {
response.pipe(file);
});
file.push(res);
});
module.exports = router;
error I am getting is
TypeError: file.push is not a function
at router.get (/root/adstichrplayer/server/routes/podcast.js:131:10)
at Layer.handle [as handle_request] (/root/node_modules/express/lib/router/layer.js:95:5)
at next (/root/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/root/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/root/node_modules/express/lib/router/layer.js:95:5)
at /root/node_modules/express/lib/router/index.js:281:22
at param (/root/node_modules/express/lib/router/index.js:354:14)
at param (/root/node_modules/express/lib/router/index.js:365:14)
at param (/root/node_modules/express/lib/router/index.js:365:14)
at Function.process_params (/root/node_modules/express/lib/router/index.js:410:3)
at next (/root/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/root/node_modules/express/lib/router/index.js:174:3)
at router (/root/node_modules/express/lib/router/index.js:47:12)
at Layer.handle [as handle_request] (/root/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/root/node_modules/express/lib/router/index.js:317:13)
at /root/node_modules/express/lib/router/index.js:284:7
You are trying to use .push on a Writeable stream. Only streams that implement a Readable interface can call .push.
If you don't specifically need to persist the file to disk, there's no reason to create the WriteStream. You can pipe directly to Express' res object:
router.get('/a/:url(*)', (req, res) => {
res.set({
'Content-Type': 'audio/mp3',
// 'Transfer-Encoding': 'chunk',
// 'Content-Disposition': 'attachment'
});
const url = req.params.url.substr(0);
console.log(url);
https.get(url, mp3Response => {
// pipe response from HTTP request to Express res object
mp3Response.pipe(res);
});
});

What to log to debug Error [ERR_HTTP_HEADERS_SENT]?

In an Express controller function, I am running into to this error Error [ERR_HTTP_HEADERS_SENT]. This occurs when I call res.json() if headers have already been set on the res object. However, I don't see place in my function (or middleware) where headers could be set prior to my calling res.json().
To debug the cause of this error, I thought I could add some logging. Prior to calling res.json, I could check if headers had been set and, if so, log some information about who set them.
async function get(req, res) {
...
if (res._header) {
logger.debug(...);
}
res.json(...);
Unfortunately, I don't see anything useful in the res object to log, any message that would indicate why/how the headers were set (or who set them). Any suggestions for what I could log to debug this issue? Or other debugging suggestions?
You can patch res.header res.send res.set to log the stack trace for you. For example this is my main application.
const express = require('express');
const app = express();
const someGoody = require('./stupid-blackbox');
/** patch the res **/
app.use((req, res, next) => {
const _header = res.header.bind(res); // .header and .set is an alias pair
const _send = res.send.bind(res);
res.header = res.set = (field, val) => {
console.trace('.header/.set called', field, val);
console.log('-----');
return _header(field, val);
}
res.send = (body) => {
console.trace('.send called', body);
console.log('-----');
return _send(body);
}
next();
})
// some innocent looking middleware
app.use(someGoody);
// my main routes
app.get('*', (req, res) => {
res.json({url: req.url});
})
app.listen(3000);
And for stupid-blackbox.js:
const express = require('express');
const router = express.Router();
router.use((req, res, next) => {
res.header('X-Crash-You', '1').send(':)');
next();
})
module.exports = router;
When ran, you will get this in the log:
Trace: .header/.set called X-Crash-You 1
at ServerResponse.res.header.res.set (C:\Users\eric_\Desktop\initial\play\index.js:11:13)
at router.use (C:\Users\eric_\Desktop\initial\play\stupid-blackbox.js:6:9)
at Layer.handle [as handle_request] (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:317:13)
at C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:275:10)
at Function.handle (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:174:3)
at router (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:47:12)
at Layer.handle [as handle_request] (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\layer.js:95:5)
-----
Trace: .send called :)
at ServerResponse.res.send (C:\Users\eric_\Desktop\initial\play\index.js:17:13)
at router.use (C:\Users\eric_\Desktop\initial\play\stupid-blackbox.js:6:36)
at Layer.handle [as handle_request] (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:317:13)
at C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:275:10)
at Function.handle (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:174:3)
at router (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\index.js:47:12)
at Layer.handle [as handle_request] (C:\Users\eric_\Desktop\initial\play\node_modules\express\lib\router\layer.js:95:5)
On the second line of each stack trace you can see the stupid-blackbox.js.
On a side note, res.json will not result in error if only res.header or res.set is called, the error is headers has been sent so that means somewhere in the code, res.send is called causing headers to be sent before your actual code.

Nodejs Express POST 404 Not Found error on live, working on localhost

I recently changes my domain (and SSL certificate) on my live server and since then I have been not able to POST to my node.js express app.
GET is working perfectly fine and POST is working on localhost but my live app is returning a 404 error whenever I send a POST request.
Error stack trace shows:
Error: Not Found
at /opt/bitnami/apps/tot/app.js:63:15
at Layer.handle [as handle_request] (/opt/bitnami/apps/tot/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:317:13)
at /opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:335:12)
at next (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:275:10)
at allowCrossDomain (/opt/bitnami/apps/tot/app.js:56:5)
at Layer.handle [as handle_request] (/opt/bitnami/apps/tot/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:317:13)
at /opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:335:12)
at next (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:275:10)
at SendStream.error (/opt/bitnami/apps/tot/node_modules/serve-static/index.js:121:7)
at SendStream.emit (events.js:200:13)
at SendStream.error (/opt/bitnami/apps/tot/node_modules/send/index.js:270:17)
at SendStream.onStatError (/opt/bitnami/apps/tot/node_modules/send/index.js:421:12)
I have a very simple app:
require('dotenv').config();
const express = require('express');
const app = express();
const helmet = require('helmet');
//const morgan = require('morgan'); //logging requests to console
//const fileUpload = require('express-fileupload');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const path = require('path');
const startupDebugger = require('debug')('tot:startup');
const mongoDebugger = require('debug')('tot:mongo');
const port = process.env.WEB_PORT;
// configure middleware
app.set('port', process.env.port || port); // set express to use this port
//app.set('views', __dirname + '/views'); // set express to look in this folder to render our view
app.set('view engine', 'ejs'); // configure template engine
app.use(helmet());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json()); // parse form data client
app.use(express.static(path.join(__dirname, 'public'))); // configure express to use public folder
//app.use(fileUpload()); // configure fileupload
const urlencodedParser = bodyParser.urlencoded({ extended: false })
// --- Routes ---
const {getHomePage} = require('./routes/index');
const {playground} = require('./routes/playground');
const {getMessage} = require('./routes/slack/events-api');
const {getComponent} = require('./routes/slack/interactive-components');
const {renderSurvey} = require('./routes/feedback/survey');
const {score} = require('./routes/feedback/score-api');
app.get('/', getHomePage);
app.get('/playground', playground);
// Slack APIs
app.post('/slack/events-api', getMessage);
app.post('/slack/interactive-components', urlencodedParser, getComponent);
//Feedback
app.get('/feedback/survey/:team_id/:user_id/:question_id/:date', renderSurvey);
app.post('/feedback/score', score);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
console.error(err.stack);
next(err);
});
app.listen(port, () => { startupDebugger(`Server running on port: ${port}`); });
mongoose.connect(process.env.MONGO, { useNewUrlParser: true })
.then(() => mongoDebugger('Connected to MongoDB.'))
.catch(error => mongoDebugger('MongoDB Error: '+error));
Here is an example for /slack/events-api
getMessage: async function (req, res) {
//console.log(req);
let payload = req.body;
console.log('Payload:');
console.dir(payload, {depth: null});
slackDebugger('Slack Event API Challange Request');
res.render('slack/events-api.ejs', {
title: "Slack Bot"
, output: req.body.challenge
});
}
}
When I post via Postman locally it works fine:
[nodemon] starting `node app.js`
tot:startup Server running on port: 3000 +0ms
tot:mongo Connected to MongoDB. +0ms
Payload:
{ token: 'Jhj5dZrVaK7ZwHHjRyZWjbDl',
challenge: '3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P',
type: 'url_verification' }
tot:slack Slack Event API Challange Request +0ms
On the live server:
[nodemon] starting `node app.js`
tot:startup Server running on port: 3000 +0ms
tot:mongo Connected to MongoDB. +0ms
Error: Not Found
at /opt/bitnami/apps/tot/app.js:63:15
at Layer.handle [as handle_request] (/opt/bitnami/apps/tot/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:317:13)
at /opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:335:12)
at next (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:275:10)
at allowCrossDomain (/opt/bitnami/apps/tot/app.js:56:5)
at Layer.handle [as handle_request] (/opt/bitnami/apps/tot/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:317:13)
at /opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:335:12)
at next (/opt/bitnami/apps/tot/node_modules/express/lib/router/index.js:275:10)
at SendStream.error (/opt/bitnami/apps/tot/node_modules/serve-static/index.js:121:7)
at SendStream.emit (events.js:200:13)
at SendStream.error (/opt/bitnami/apps/tot/node_modules/send/index.js:270:17)
at SendStream.onStatError (/opt/bitnami/apps/tot/node_modules/send/index.js:421:12)
I cannot for the life of me work out why this has suddenly stopped working on live since updating the live URL/SSL.
If anybody can point me in the right direction that would be amazing.

Resources