Creating a Vue.js Serverless Checkout Form: Stripe Function and Hosting

Avatar of Sarah Drasner
Sarah Drasner on (Updated on )

We’re now in the second post of a four-part series where we’re creating a checkout form application in Vue.js that can accept payments via the Stripe API. In part one, we looked at the concept of serverless functions, set one up in Azure, and connected it to a Stripe account. In this post, we’ll focus on setting up Stripe as a serverless function and hosting it all on Github.

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting (This Post)
  3. Application and Checkout Component
  4. Configure the Checkout Component

First, we’re going write our function and test it out in the portal, but eventually we’re going to move it over to Github and have Azure pull in the code. I’ll explain why we do this in a moment.

For now, in order to get it working and testable, we’re going to write it in the portal and fill in the request body to perform the test. But we need to know what Stripe will expect from us first.

Dun dun dun…

Working With Stripe as a Serverless Function

If you check out Stripe’s documentation, you can see that we’ll need to grab the Stripe token in the dashboard. This will eventually mirror the POST parameters submitted by our form. Stripe makes it easy, so it’s fairly straightforward to use their library for the server-side function with Express:

app.get('/', (req, res) => res.render('index.pug', { keyPublishable }));

app.post('/charge', (req, res) => {
  let amount = 500;

  stripe.customers
    .create({
      email: req.body.stripeEmail,
      source: req.body.stripeToken
    })
    .then(customer =>
      stripe.charges.create({
        amount,
        description: 'Sample Charge',
        currency: 'usd',
        customer: customer.id
      })
    )
    .then(charge => res.render('charge.pug'));
});

app.listen(4567);

We won’t need to set up all of Node and Express for this, though, as what we really need is the amount, the currency, the description, and the token, which we can integrate with the testing code we were provided earlier in the portal’s view of our function. So, let’s head over to the Azure portal where our function lives and update that default testing code to accept the parameters we need for Stripe, and also populate the request.body in the test panel.

We’ll add our Stripe testing key and kick everything off. To be totally sure, we’re going to log what we’ve gotten started:

var stripe = require('stripe')('sk_test_whateveryourtestingkeyisgoeshere');
// ^ this is a stripe testing key

module.exports = function(context, req) {
  context.log('starting to get down');

If we have a request body, an email, and a token, then let’s get started. We’ll create a customer from the email and then use that customer to create the Stripe charges, passing in the amount of the charge as we do so.

if (
  req.body &&
  req.body.stripeEmail &&
  req.body.stripeToken &&
  req.body.stripeAmt
){
  stripe.customers
    .create({
      email: req.body.stripeEmail,
      source: req.body.stripeToken
    })
    .then(customer => {
      context.log('starting the stripe charges');
      stripe.charges.create({
        amount: req.body.stripeAmt,
        description: 'Sample Charge',
        currency: 'usd',
        customer: customer.id
      });
    })
      ...

We also want to test if this all completed successfully, or if it errored out. If it did error, we need to log what that error is. We’ll also see if the whole thing errored entirely, making sure we’re logging everything appropriately along the way.

You’ll note that I log a lot. I think it’s not enough to know that something has errored. I want to know when the error happened and why so that I can track it down. This makes it much easier to debug if something were to go wrong.

      ...
      .then(charge => {
        context.log('finished the stripe charges');
        context.res = {
          // status: 200
          body: 'This has been completed'
        };
        context.done();
      })
      .catch(err => {
        context.log(err);
        context.done();
      });
  } else {
    context.log(req.body);
    context.res = {
      status: 400,
      body: "We're missing something"
    };
    context.done();
  }
};

In the testing area on the right side of the portal, we’ll fill the request.body with the stripeEmail, stripeToken (a testing token in this case), and some random amount for the charge. When we run this, we can see that it works! We get a 200 OK Status, and we’ve logged This has been completed in the output.

actual function with testing request body params
Testing the request body parameters with the actual function in Azure.

Github-Hosted Serverless Function

Let’s put everything in Github now that it’s working. One big reason we want to do this is because our function will have a dependency on Stripe’s library. If you head over to the sample-stripe-handler repo I’ve created for this tutorial, you’ll see a package.json file. The most important lines in that file are these:

"dependencies": {
  "stripe": "^5.3.0"
}

This tells the function to pull in the correct version of the Stripe API that we need to use in order for our app to properly function. As a note, you could also use this method to write other kinds of functions using other libraries. This means the possibilities for what to create are endless!

We’ll pull everything from our function into this repo. This includes the function itself, the package.json file, as well as the contents of the function.json file that you’ll see in the “View Files” tab on the right in the Azure portal.

Once we have that all in ready to go in a Github repo, we’ll head back over to the Azure portal, because now we have to let Azure know that we’d like to use this repo to host our function instead of our test. We can still test our function inside the portal—we just won’t be able to edit it via the GUI anymore.

Click on the “Platform Features” tab and select the “Deployment Options” item.

Azure Portal Deployment Options

From here, click “Settings” then “Choose source” and a number of options will be provided. I’m going to choose Github because that’s where I want to host mine, but you can see that there are a lot of other ways we could have done this.

Choose github
Deployment settings source options, including Github.

Once Github has been selected, you will be able to configure which repo you would like to use as your deployment source. I chose the sample-stripe-handler repo that we created earlier.

Choose github repo for deployment option
Configuring Github as the deployment source.

After we’ve done this and it’s loaded, you’ll be taken to a “Deployments” screen that shows the last commit that you made to the repo. That means everything’s working correctly!

first deploy

Let’s test this a little further. My function didn’t work properly the first time because I was using ES6. I could have added in Babel, but I just converted it back to ES5 and pushed to the master branch. You can see the function.json becomes inactive as the last deployment, and my latest commit message—which is mostly me grumbling—is now the latest deploy! Awesome.

New deployment working

We can’t be too careful so, to check that these tests did indeed work, I’m going to head over to the Stripe dashboard. Sure enough, there are testing charges showing up in our dashboard 😀

Stripe dashboard with a little activity

One last thing!

We would be remiss to exclude our good friend CORS, which we need to properly enable for everything to communicate as it should. Let’s go to our function in the dashboard, and select CORS:

select cors

In the prompt that appears, we’ll whitelist our localhost dev server, as well as our final URL for the site. Voila! We’re all set.

whitelist localhost

Next Up…

We got a lot done in this post! Next, we’ll want to learn how to move away from testing only within the function and get this sucker communicating freely with a checkout experience that we’ll build within a Vue.js application. Stay tuned!

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting (This Post)
  3. Application and Checkout Component
  4. Configure the Checkout Component