Search code examples
node.jsmeteormultipartform-datamulter

Receiving Multi-Part Form Data with Meteor + Multer?


I have express-oriented sample code for receiving multi-part form data from a provider:

const multer = require('multer');
const callback = multer();

app.post('/callback', callback.single('json'), (req, res) => {
  res.status(200);
  res.send('API Event Received');

  const data = req.body.json;
  const events = JSON.parse(data);
  const eventType = events.event.event_type;
  const signatureRequestId = events.signature_request.signature_request_id;

  switch(eventType) {
    case 'signature_request_sent':
      console.log(`Signature request ${signatureRequestId} has been sent.`);
      break;
    case 'signature_request_viewed':
      console.log(`Signature request ${signatureRequestId} has been viewed.`);
      break;
    case 'signature_request_downloadable':
      console.log(`Signature request ${signatureRequestId} is downloadable.`);
      break;
    case 'signature_request_signed':
      console.log(`Signature request ${signatureRequestId} has been signed.`);
      break;
    case 'signature_request_declined':
      console.log(`Signature request ${signatureRequestId} has been declined.`);
      break;
    default:
      console.log('');
      break;
  }

});

On this SO post, I saw an example of connecting Meteor to Multer for purposes of receiving image files:

if (Meteor.isServer) {
  Meteor.startup(function () {
    multer({ dest: './uploads/',
        rename: function (fieldname, filename) {
            return filename+Date.now();
        },
        onFileUploadStart: function (file) {
            console.log(file.originalname + ' is starting ...');
        },
        onFileUploadComplete: function (file) {
            console.log(file.fieldname + ' uploaded to  ' + file.path);
            var fileName = file.name;
            var done=true;
        }
    })
  });
}

...but I haven't figured out yet how to combine the two code samples.

What's the correct way to use Multer in Meteor to receive multi-part form data?

UPDATE: A commenter asked what I had tried so far. I have this Meteor code that creates regular, single-part REST endpoint:

WebApp.connectHandlers.use('/ReceiveCalls', (req, res, next) => {
    console.log('received message');
    console.log( req);
    console.log(res);
    res.writeHead(200);
});

The Multer sample show above, includes a destination folder to receive images, but it doesn't show how to create the endpoint. The Meteor code shows how to create a REST endpoint, but I can't yet see how to combine it with the Multer code. I'm sure it's pretty easy, but I haven't yet figured out how to do it.


Solution

  • Here's the answer, via coagmano on the Meteor forum:

    Note: in case it may be useful to others, the provider is HelloSign. Here's my completed code.

    //TELL HELLOSIGN THE CALLBACK URL
    const hellosign = require('hellosign-sdk')({key: 'xxxxx'});
    hellosign.account.update({
        callback_url: 'https://example.com/myCallBackURL'
    }).then((res) => {
        console.log('success setting hellosign account callback url');
    }).catch((err) => {
        console.log('error setting hellosign account callback url');
        console.log(err)
    });
    
    //REST API FOR HELLOSIGN
    const callback = multer({dest: './uploads'});
    
    // Mount the middleware first so it's run first
    WebApp.connectHandlers.use('/myCallBackURL', callback.single('json'));
    
    // Then mount the user handler
    WebApp.connectHandlers.use('/myCallBackURL', (req, res, next) => {
        res.setHeader('Content-Type', 'text/html');
        res.setHeader('X-Foo', 'bar');
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Hello API Event Received');
    
        const data = req.body.json;
        const events = JSON.parse(data);
        const eventType = events.event.event_type;
        const signatureRequestId = events.signature_request.signature_request_id;
    
        switch (eventType) {
            case 'signature_request_sent':
                console.log(`Signature request ${signatureRequestId} has been sent.`);
                break;
            case 'signature_request_viewed':
                console.log(`Signature request ${signatureRequestId} has been viewed.`);
                break;
            case 'signature_request_downloadable':
                console.log(`Signature request ${signatureRequestId} is downloadable.`);
                break;
            case 'signature_request_signed':
                console.log(`Signature request ${signatureRequestId} has been signed.`);
                break;
            case 'signature_request_declined':
                console.log(`Signature request ${signatureRequestId} has been declined.`);
                break;
            default:
                console.log('');
                break;
        }
    });