Search code examples
node.jsrestmeteortwiliotwilio-twiml

Empty params on Twiml POST request


A little background. I have a web app running that is attempting to receive incoming texts from Twilio. I have configured Twilio's sms twiml url to point to a route in my app at:

http://my-app-name.com/api/twiml

I have some code executed when the request has been made:

if (Meteor.server) {
    // use picker to make a server side route
    Picker.route('/api/twiml', (params, req, res, next) => {
        console.log(util.inspect(params, {showHidden: true, colors: true}));
        console.log(util.inspect(req.body, {showHidden: true, colors: true}));

        // message data (not populating?)
        let messageSid = params.query.MessageSid,
            accountSid = params.query.AccountSid,
            from = params.query.From,
            to = params.query.To,
            body = params.query.Body;

        //console.log(messageSid + '\n' + accountSid + '\n' + from + '\n' + to + '\n' + body)

        //from = '+' + from.trim();
        //to = '+' + to.trim();

        let responseBody = 'Thanks';

        res.writeHeader(200, {'Content-Type': 'application/xml'});

        return '<?xml version="1.0" encoding="UTF-8"?><Response><Sms from="[TWILIOFROM]" to="[TO]">[BODY]</Sms></Response>'
            .replace('[TWILIOFROM]', myNumber)
            .replace('[TO]', from)
            .replace('[BODY]', responseBody);
    });
}

When I text my twilio number the code runs but I'm getting a 11200 HTTP retrieval failure error in my Twilio logs. My app's logs are outputting the first console.log's but I'm not receiving any data from my params.query.

{ query: {} }

The second console.log: console.log(util.inspect(req.body, {showHidden: true, colors: true})); spits out some garbage: [90mundefined[39m

Should I give up parameters and try to parse the request body?

I'm very new to REST api's so I'm sure that I'm missing something pretty basic.


Solution

  • Twilio developer evangelist here.

    When Twilio POSTs to your configured SMS url, the parameters are sent as the body of the request, not as query string parameters.

    I'm not too familiar with Picker, but the documentation suggests you can use Express middleware, including body-parser. If you hook up Picker with body-parser then you should be able to get the parameters from req.body. Something like this might work (note lines 2 and 3, including body-parser):

    if (Meteor.server) {
        var bodyParser = Meteor.npmRequire( 'body-parser');
        Picker.middleware( bodyParser.urlencoded( { extended: false } ) );
    
        // use picker to make a server side route
        Picker.route('/api/twiml', (params, req, res, next) => {
            console.log(util.inspect(params, {showHidden: true, colors: true}));
            console.log(util.inspect(req.body, {showHidden: true, colors: true}));
    
            // message data (not populating?)
            let messageSid = req.body.MessageSid,
                accountSid = req.body.AccountSid,
                from = req.body.From,
                to = req.body.To,
                body = req.body.Body;
    
            //console.log(messageSid + '\n' + accountSid + '\n' + from + '\n' + to + '\n' + body)
    
            //from = '+' + from.trim();
            //to = '+' + to.trim();
    
            let responseBody = 'Thanks';
    
            res.writeHeader(200, {'Content-Type': 'application/xml'});
    
            let twiml =  '<?xml version="1.0" encoding="UTF-8"?><Response><Sms from="[TWILIOFROM]" to="[TO]">[BODY]</Sms></Response>'
                .replace('[TWILIOFROM]', myNumber)
                .replace('[TO]', from)
                .replace('[BODY]', responseBody);
    
            res.end(twiml);
        });
    }
    

    Let me know if this helps at all.

    EDIT: I think that, instead of returning the TwiML, you actually need to send it to the response object with res.send. I've updated the code above.