2

I'm simply trying to build an auto-subscription API which POSTs back the token. I can do this very easily in Sinatra (render the POSTed JSON from AWS) -- seem to be having a hard time in Express; I'm sure it's just something stupid I'm missing, though I've tried 1000X combinations.

Here is the Sinatra webserver:

# application.rb

require 'rubygems'
require 'sinatra'
require 'json'

set :port, 8081

post '/webservice/cloudwatch' do
  content_type :json
  puts "Body: " + request.body.read
end

Which logs:

- -> /webservice/cloudwatch
Body: {
  "Type" : "SubscriptionConfirmation",
  "MessageId" : "OMIT",
  "Token" : "OMIT",
  "TopicArn" : "OMIT",
  "Message" : "OMIT",
  "SubscribeURL" : "OMIT",
  "Timestamp" : "2012-02-28T21:28:02.082Z",
  "SignatureVersion" : "1",
  "Signature" : "OMIT",
  "SigningCertURL" : "OMIT"
}

Here is the Express webserver:

var express, app, stache;
express = require("express"), app = express.createServer();
app.configure(function () {
  app.use(express.methodOverride());
  app.use(express.bodyParser());
  app.use(app.router);
  app.set("view options", {
    layout: false
  });
  app.use(express.errorHandler({
    dumpExceptions: true,
    showStack: true
  }));
});
app.post("/webservice/cloudwatch", function (request, response) {
  request.accepts('application/json');
  console.log("post body: " + JSON.stringify(request.params));
  console.log("post body: " + JSON.stringify(request.body.read));
});  
app.listen(8081);

Which logs:

post body: []
post body: undefined

Please help!

  • instead of doing a `console.log` on `request.body.read` try doing a `console.dir` on `request.body` and see what attributes it contains. – Marshall Feb 28 '12 at 21:34
  • console.dir(request.body); This logs {} –  Feb 28 '12 at 21:39
  • console.dir(request.body.read); This logs undefined –  Feb 28 '12 at 21:40
  • Okay. Take a look at the [Node Docs on ServerRequest objects](http://nodejs.org/docs/latest/api/all.html#http.ServerRequest). I'm not familiar with Sinatra, but maybe you are looking for `request.headers`. – Marshall Feb 28 '12 at 21:45

3 Answers3

2

When amazon sends the http post request to your endpoint, it doesn't specify a content type. This is a known issue for them, based on their responses.

In the meantime there is a very hacky workaround I've been testing. I modified the bodyParser.js file in the express plugin. Specifically, I added an if check to the mime function such that I can force it to pretend the content-type is application/json as necessary.

Here is the modified mime function:

function mime(req) {
    if(req.headers['x-amz-sns-message-type'] == 'SubscriptionConfirmation' && !req.headers.hasOwnProperty['content-type']) {
        req.headers['content-type'] = 'application/json';
    }

    var str = req.headers['content-type'] || '';
    return str.split(';')[0];
}
Perception
  • 79,279
  • 19
  • 185
  • 195
Dmurker
  • 21
  • 2
1

Which request are you using to test your webservice? Doing:

curl -H "Content-Type: application/json" -d '{"Type":"SubscriptionConfirmation","MessageId":"OMIT","Token":"OMIT","TopicArn":"OMIT","Message":"OMIT","SubscribeURL":"OMIT","Timestamp":"2012-02-28T21:28:02.082Z","SignatureVersion":"1","Signature":"OMIT","SigningCertURL":"OMIT"}' http://localhost:8081/webservice/cloudwatch

(notice the content-type set to application/json) and changing your console.log to console.log(request.body); should give you the expected results. The bodyParser method needs to know the content-type to correctly populate request.body.

Guitan
  • 375
  • 2
  • 4
0

Add the following to your express server (make sure bodyParser comes after rawbody). Try logging request.rawbody

var rawbody = function(req, res, next) {
    var data = '';
    req.setEncoding('utf8');
    req.on('data', function(chunk) {
        data += chunk;
    });
    req.on('end', function() {
    req.rawBody = data;
        next();
    });
};

app.use(rawbody);
app.use(express.bodyParser());

Thanks to: Expressjs raw body

Community
  • 1
  • 1
Brian
  • 147
  • 1
  • 4