9

Really struggling to get this working. I have a webhook definition setup in Contentful. When I publish an entry in Contentful it sends an HTTP POST request to webhooks.example.com.

At that subdomain I have a NodeJS server running to accept the request. I've looked at the Contentful API docs, which say the request body should contain the newly published entry.

I've tried 2 methods of receiving the request, neither of which are giving me anything for the request body. First I tried the contentful-webhook-server NPM module:

var webhooks = require("contentful-webhook-server")({
  path: "/",
  username: "xxxxxx",
  password: "xxxxxx"
});

webhooks.on("ContentManagement.Entry.publish", function(req){
  console.log("An entry was published");
  console.log(req.body);
});

webhooks.listen(3025, function(){
  console.log("Contentful webhook server running on port " + 3025);
});

Here the request comes through and I get the message An entry was published but the req.body is undefined. If I do console.log(req) instead, I can see the full request object, which doesn't include body.

So I then tried running a basic Express server to accept all POST requests:

var express = require("express"),
    bodyParser = require("body-parser"),
    methodOverride = require("method-override");

var app = express();
app.use(bodyParser.json({limit: "50mb"}));
app.use(bodyParser.urlencoded({extended:true}));
app.use(methodOverride("X-HTTP-Method-Override"));

app.post("/", function(req, res){
  console.log("Incoming request");
  console.log(req.body);
});

Again with this, I get the Incoming request message but req.body is empty. I know this method is wrong because I haven't used my webhook username/password.

How do I correctly receive incoming webhook requests and get the body content?

CaribouCode
  • 13,998
  • 28
  • 102
  • 174
  • First of all: You forget to use `app.listen(#portNumber)`. I added that line and tried the `curl` example from contentful-webhook-server: `curl -X POST --header "X-Contentful-Topic: ContentManagement.Entry.publish" localhost:#portNumber`. It worked for me. Do you still notice any issues after adding that line? – Florian Wendelborn May 28 '15 at 01:01
  • @FlorianW. Yes I had the `app.listen` code, just not in my example above. It receives the incoming requests, but the entry is not included in the body as expected. It looks like it should according to the API docs for Contentful. – CaribouCode May 28 '15 at 11:25
  • have you tried writing the incoming stream to your console using `req.pipe(process.stdout);` for example? The incoming message is of type https://nodejs.org/api/http.html#http_http_incomingmessage as far as I can see from the npm module docs.. – VF_ May 28 '15 at 12:29
  • Can you try to use [http-body-parse](https://www.npmjs.com/package/http-body-parse) with contentful-webhook-server? As I don't have a contentful account I can't test that alone. – Florian Wendelborn May 29 '15 at 12:33
  • It sounds like you're saying: Site 1 sends a CGI request to Site 2. Site 2 gets the querystring content but not the body of Site 1. Isn't this the way that CGI works? If "Site 1" is my website and "Site 2" is Facebook.com, for example, would I really want Facebook to have access to my web page's BODY if I call one of their APIs? No. Sorry if I don't understand Webhooks but from what you've described this is how it works. – Michael Blankenship Jun 01 '15 at 01:46

2 Answers2

14

The contentful-webhook-server does not parse the req so that would explain why it does not deliver the body to you in the callback.

Your server seem to be correct but it seems that contentful has a custom json type that is not recognized by the type-is library.

the content-type looks like 'application/vnd.contentful.management.v1+json'

your server will probably work if you make body-parser accept this custom content type. For example :

app.use(bodyParser.json({type: 'application/*'}));

If this works, you could be more specific on the accepted type.

For the record :

typeis.is('application/vnd.contentful.management.v1+json', ['json'])
=> false
Jerome WAGNER
  • 21,986
  • 8
  • 62
  • 77
0

An easier option is to modify the custom Content-Type since we know it actually returns JSON. Just stick this somewhere above the bodyParser

app.use(function(req, res, next) {     
    if (req.headers['content-type'] === 'application/vnd.contentful.management.v1+json') req.headers['content-type'] = 'application/json';
    next();
});
sidonaldson
  • 24,431
  • 10
  • 56
  • 61