NodeJS Listener for webhooks returns empty body

Viewed 860

I have been on this for about 2 days and ready to pull my hair out.

I have a system that fires off simple Webhooks that I need to capture and parse. I have created a very simple Nodejs listener and am running Ngrok to create the public address. I am getting a request but the body is empty no matter what I do. Irrespective of content-type or app.use(bodyParser.urlencoded()).

The body still returns as {}

'use strict'

const express = require('express')
const bodyParser = require('body-parser')

// Create a new instance of express
const app = express()

// Tell express to use the body-parser middleware and to not parse extended bodies
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))

// Route that receives a POST request to /sms
app.post('/', function (req, res) {
    console.log(req);
  const body = req.body
  console.log("body")
  console.log(body);
  res.set('Content-Type', 'text/plain')
  res.send(`You sent: ${body} to Express`)
})


// Tell our app to listen on port 4545
app.listen(4545, function (err) {
  if (err) {
    throw err
  }

  console.log('Server started on port 4545')
})

However if I set up the address as https://webhook.site or https://pipedream.com then the body is indeed published. I have tried combinations of content-type, urlencode, even thinking it was gzip or something and even deploying on Azure VM and others. Nothing.

But the moment I set the address as webhooks or pipedream the data shows without issue.

After some comments I wanted to add the result (partial result) of the console.log(req):

complete: false,
    headers: {
      connection: 'Keep-Alive',
      'accept-encoding': 'gzip',
      host: 'localhost:4646',
      'max-forwards': '10',
      'user-agent': 'Go-http-client/2.0',
      'content-length': '339'
    },
    rawHeaders: [
      'Connection',
      'Keep-Alive',
      'Accept-Encoding',
      'gzip',
      'Host',
      'localhost:4646',
      'Max-Forwards',
      '10',
      'User-Agent',
      'Go-http-client/2.0',
      'X-Original-URL',
      '/',
      'Content-Length',
      '339'
    ],
    trailers: {},
    rawTrailers: [],
    aborted: false,
    upgrade: false,
    url: '/',
    method: 'POST',
    statusCode: null,
    statusMessage: null,
    client: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      readable: true,
      _events: [Object: null prototype],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: true,
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      timeout: 120000,
      parser: [HTTPParser],
      on: [Function: socketListenerWrap],
      addListener: [Function: socketListenerWrap],
      prependListener: [Function: socketListenerWrap],
      _paused: false,
      _httpMessage: [Circular],
      [Symbol(asyncId)]: 115,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: Timeout {
        _idleTimeout: 120000,
        _idlePrev: [TimersList],
        _idleNext: [Timeout],
        _idleStart: 6602,
        _onTimeout: [Function: bound ],
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(asyncId)]: 116,
        [Symbol(triggerId)]: 115
      },
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0
    },
    _consuming: false,
    _dumped: false,
    next: [Function: next],
    baseUrl: '',
    originalUrl: '/',
    _parsedUrl: Url {
      protocol: null,
      slashes: null,
      auth: null,
      host: null,
      port: null,
      hostname: null,
      hash: null,
      search: null,
      query: null,
      pathname: '/',
      path: '/',
      href: '/',
      _raw: '/'
    },
    params: {},
    query: {},
    res: [Circular],
    body: {},
    route: Route { path: '/', stack: [Array], methods: [Object] },
    [Symbol(kCapture)]: false
  },
  locals: [Object: null prototype] {},
  [Symbol(kCapture)]: false,
  [Symbol(kNeedDrain)]: false,
  [Symbol(corked)]: 0,
  [Symbol(kOutHeaders)]: [Object: null prototype] {
    'x-powered-by': [ 'X-Powered-By', 'Express' ]
  }
}

You can see that the body is empty when console.log(req)

Can anyone send me on the right path to sort this out?

Much appreciated.

2 Answers

So for anyone else who struggles with something similar, this is what I did to resolve:

I had to inject a content-type into the headers and then viola the body started to appear:

var customParser = bodyParser.json({type: function(req) {
    if (req.headers['content-type'] === ""){
        return req.headers['content-type'] = 'application/json';
    }
    else if (typeof req.headers['content-type'] === 'undefined'){
        return req.headers['content-type'] = 'application/json';
    }else{
        return req.headers['content-type'] = 'application/json';
    }
}});


app.use(bodyParser.json({
  limit: '50mb',
  extended: true
})); // support encoded bodies

app.use(bodyParser.urlencoded({
  limit: '50mb',
  extended: true
})); // support encoded bodies


app.post("/hook", customParser, (req, res) => {
    //console.log(req);
    //const fs = require('fs');
    console.log("Events req.body", req.body) // Call your action on the request here

    res.status(200).end()
  })

That did it for me.

Thanks

You can get body data in req.body Include body-parser middleware which parses the body and sets req.body property.

var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false })) 

// Route that receives a POST request to /sms
app.post('/', function (req, res) {
  console.log(req);
  const body = req.body
  console.log("body")
  console.log(body);
  res.set('Content-Type', 'text/plain')
  res.send(`You sent: ${body} to Express`)
})
Related