1

I'm using node and stripe to handle payments. I've got a /charge route setup that takes a bunch of parameters from the front end and renders a receipt.

I'm wondering how i redirect from a POST route to a GET route in order to prevent errors when someone tries to reload the page after the POST route has loaded?

These are my routes so far. I have a payment button at / that sends a POST request to /charge.

router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

router.post('/charge', function(req, res, next) {

  var stripeToken = req.body.stripeToken;
  var stripeEmail = req.body.stripeEmail;
  var amount = 3999;
  var description = "Product description";

  var charge = stripe.charges.create({
    amount: amount, // amount in cents, again
    currency: "gbp",
    source: stripeToken,
    receipt_email: stripeEmail,
    description: description
  }, function(err, charge) {
    if (err && err.type === 'StripeCardError') {
      // The card has been declined
    } else {
      res.render('charge', {
        title: 'Charge',
        descrption: charge.description,
        total: (charge.amount / 100) + charge.currency.toUpperCase(),
        trans_id: charge.id
      });
    }
  });

});

As i have it now, the /charge route errors really badly, and breaks the app if the page is reloaded after submitting. This is due to the token only being valid on first try, so the charge object is empty on all attempts after this.

What's the best way to handle this issue? Redirect to a new page? How do i get the charge values to persist on to this new page? Can i redirect to the homepage on refresh??

Any advice on this would be appreciated!

Scotty
  • 2,635
  • 6
  • 30
  • 39

2 Answers2

1

It may help you to isolate your GET/POST requests so that you don't carry around the POST data (which causes the issue you are running into). Here you can validate and process the data, then pass the results as a querystring to your GET route.

var querystring = require('querystring');

router.post('/charge', function(req, res) {
    var stripeToken = req.body.stripeToken;
    var stripeEmail = req.body.stripeEmail;
    var amount = 3999;
    var description = "Product description";
    if (!stripeToken || !stripeEmail) {
        //do something with error
        res.redirect('/charge-error');
        //or
        res.sendStatus(404);
        return;
    } 
    var charge = stripe.charges.create({
        amount: amount, // amount in cents, again
        currency: "gbp",
        source: stripeToken,
        receipt_email: stripeEmail,
        description: description
    }, function(err, charge) {
        if (err && err.type === 'StripeCardError') {
            // The card has been declined
            res.redirect('/charge-error');
        } else {
            //redirect with result
            res.redirect('/charge?' + querystring.stringify({
                title: 'Charge',
                descrption: charge.description,
                total: (charge.amount / 100) + charge.currency.toUpperCase(),
                trans_id: charge.id                
            });
        }
    });
});


router.get('/charge', function(req, res) {
    //do GET stuff
    res.render('charge', {
        title: req.query.title,
        descrption: req.query.description,
        total: req.query.total,
        trans_id: req.query.trans_id
    });
});

See: res.redirect(<location>); @http://expressjs.com/en/api.html#res.redirect

:)

Sparkida
  • 422
  • 4
  • 9
  • 1
    The other common way to persist data (including an error/success message) through one redirect is to use a cookie that immediately expires after the next successful request. Often called a flash cookie: http://stackoverflow.com/a/23161019/511200, though I can't vouch for any particular Express implementations. – danneu Jan 09 '16 at 06:03
  • Excellent. This is what i was aiming for! Like @danneu said, is there a way to create a session/cookie that expires as soon as the redirect is made? To save passing the parameters as a querystring in the url? – Scotty Jan 09 '16 at 10:31
  • @Scotty: I don't use Express, but just as an example, here's my incomplete attempt to port my Koa solution to Express middleware: https://gist.github.com/danneu/daa2105b1316276974d0 - It doesn't work since I'm not sure how you can write Express middleware that runs after the request has been processed (but before response has been sent) so I can clear the flash cookie on success responses, but maybe it can help illuminate how flash sessions are usually implemented. – danneu Jan 09 '16 at 23:44
  • @Scotty See: `res.clearCookie` http://expressjs.com/en/api.html#res.cookie At this point though, if you have users/customers and are needing to make use of cookies and flash data, I would look at using sessions: See: https://www.npmjs.com/package/express-session Then your user will persist and the data is encrypted server-side. You can then easily access your user with `req.session`. By default these users are stored in your server's memory, which won't be a problem if you don't have many users, but you'll definitely want to upgrade that to a database as your demand grows. – Sparkida Jan 10 '16 at 17:26
0

I would re-direct them to a success/failure page. POST request. Another option would be to handle the POST with an API endpoint which would give you more control over the page the user is interacting with than an old-fashioned form POST.

errata
  • 23,596
  • 2
  • 22
  • 32
  • this is not what the OP is asking for. Also: - $window.location does not exist in Node, what the OP is using - the OP is handling the POST with an API endpoint, its location is `/charge` – Sparkida Jan 08 '16 at 19:57