Serverless Payments with Stripe and AWS Lambda
Get started on executing a program that will allow you to take card payments using the cloud and client-side tokenization.
Join the DZone community and get the full member experience.
Join For FreeIn this tutorial, we will build a serverless payment application with Stripe and AWS Lambda.
Try the Live Demo! The source code for both backend and frontend is available on GitHub.
Note that this is a bare-bones implementation and is not production ready.
What is Serverless?
When we say “serverless,” it doesn’t mean servers are no longer involved. It means that you no longer need to think about them.
Serverless is an approach that aims to eliminate the need to manage infrastructure by:
- Using a managed FaaS compute service such as AWS Lambda, Webtask, Google Cloud Functions, and IBM OpenWhisk to execute code,
- Leveraging third-party services and APIs, and
- Applying serverless architectures and patterns.
By making use of third-party services, developers can build loosely coupled, scalable, and efficient architectures quickly. Instead of building things from scratch, we connect prefabricated parts together. Today, we can rely on an abundance of third party services for payments, email, analytics, and many more.
This ecosystem of services accelerates software development. We can focus more on our core value propositions instead of secondary capabilities such as email infrastructure and server maintenance.
Serverless frees the software developer from deployment concerns so you can move fast, iterate quickly, and scale.
Functions-as-a-Service (FaaS)
FaaS providers such as AWS Lambda offer a new kind of platform that lets you deploy and invoke ephemeral (short-lived) function processes via events to handle individual requests.
Ephemeral function processes are created when an input is received, and disappears after the code finishes executing. The platform handles the provisioning of instances, termination, monitoring, logging, and so on.
Think of Serverless functions as ‘MeeSeeks’ of cloud computing.
Meeseeks are creatures created to serve a singular purpose for which they will go to any length to fulfill. After they serve their purpose, they expire and vanish into the air.
– From the ‘Rick and Morty’ Wiki
Like MeeSeeks, function processes vanish once executed.
Capacity Planning in FaaS
With traditional deployments, you can over-provision and under-provision compute capacity. This is especially true when your traffic load is unpredictable.
Image credits to getshifter.io
When you over-provision, you’re wasting money on idle compute time. When you under-provision, you can’t adequately serve your users. Compute capacity is usually over-provisioned, and for good reason.
With FaaS, the provisioned capacity will always be equal to the actual usage. There is no under or over provisioning. Each request spawns an ephemeral function process that executes your function. The FaaS provider handles the horizontal scaling automatically. If your system needs to be processing 100 requests in parallel, the provider will spawn that many function invocations without any extra configuration on your part. You only pay for the compute capacity used.
PaaS vs. FaaS
The table below highlights the differences between PaaS and Faas:
Platform-as-a-Service (PaaS) | Function-as-a-Service (FaaS) | |
---|---|---|
Startup time | Starts in minutes | Starts in milliseconds |
Running time | Runs 24 / 7 | Runs when processing an incoming request |
Cost | Monthly billing cycles | Pay for usage, in invocations and duration |
Unit of code | Monolithic app | Single-purpose, self-contained functions |
In summary, FaaS providers offers developers the ability to build services that react to events, that auto-scale, that you pay for per-execution, and that take advantage of a larger ecosystem of third-party services.
Prerequisites
If you’d like to follow along, make sure you’ve completed the following steps.
1. Stripe
Stripe is a platform for handling online payments. Make sure that you’ve signed up for Stripe, and access your dashboard.
Toggle the Test
mode and obtain the following from the API
dashboard:
- Your publishable API key
- Your secret API key
We need both keys for our application. The publishable API key is used to tokenize customer cards, and the secret API key is used to process charges via the Stripe API.
2. Serverless
The Serverless framework (serverless
) is a Node.js command-line interface (CLI) that helps you develop and deploy your serverless functions, along with the infrastructure resources they require.
serverless
makes it easy to organize all the relevant resources your application needs in order to run. Write your function code, add event triggers, and deploy it with the help of serverless
to the FaaS provider of your choice. Functions are automatically deployed and events are compiled into the syntax your FaaS provider understands.
serverless
is provider and runtime agnostic, so you are free to use any of the supported FaaS providers and languages.
Install the serverless
node module with npm
or yarn
. In your terminal, do:
Let’s check that serverless
has been installed:
3. Amazon Web Services (AWS)
We’ll be using AWS as our FaaS provider. If you haven’t already, sign up for an AWS account.
The next thing we need to do is to create an AWS user which has administrative access to your account. This lets the Serverless Framework configure the services in your AWS account.
- Login to your AWS account
- Go to the Identity & Access Management (IAM) page
- Click on the Users sidebar link
- Click on the Add user button
- Enter serverless-admin, tick the Programmatic access Access type checkbox, and click Next:Permissions
- Click Attach existing policies directly, tick Administrator Access, and click Next: Review
- Review your choices, then click Create user
- Save the Access key ID and Secret access key of the newly created user
Done! We’ve now created a user which can perform actions in our AWS account on our behalf (thanks to the Administrator Access policy).
Finally, we’ll pass the user’s API Key & Secret to serverless
. With the serverless
framework installed on your machine, do:
serverless config credentials --provider aws --key <your_aws_key> --secret <your_aws_secret>
4. Yarn
We use yarn
in place of npm
.
Hands-On
Using card information with Stripe is a two-step process:
- Securely collect payment information using tokenization (Performed in the Frontend using the Stripe publishable API key)
- Use the payment information in a charge request or save it for later (Performed in the Backend using the Stripe secret API key)
When a user enters their payment information on the Stripe Checkout embeddable form, client-side tokenization occurs.
Client-side tokenization is the method Stripe uses to collect card information directly from your customers in a secure manner. During this process, a token representing this information is returned to your backend server for use in a charge request (or to save the card details for later use). Tokens can only be used once and expire within a few minutes.
Tokenization ensures that no sensitive card data ever needs to touch your server so your integration can operate in a PCI compliant way. If any card data were to pass through or be stored on your server, you would be responsible for any PCI DSS guidelines and audits that are required.
Frontend Application
The frontend is responsible for securely collecting card information from your customers. It’s written in Next.js and React.
Below is the PayButton
component that is core to our payments flow.
After a successful tokenization request to the Stripe API, we make a POST request containing the token and payment details to a URL where our backend lives.
Backend Application
The token returned by our frontend is used by our backend to process the actual charge (through a Stripe API call.)
Our serverless ‘nanoservice’ is composed of single-purpose, granular functions. The Serverless framework uses a DSL that describes the shape of our services. Take a look at the serverless.yml
which describes our project:
Our service has a single function createCharge
whose source code is in /functions/createCharge.js
and can be triggered by HTTP POST events to the/charges
route.
The three key abstractions of serverless
applications are Functions, Events, and Resources:
- Functions are pieces of single-purpose code deployed in the cloud. When deciding what should go in a function, think of the Single Responsibility Principle or the Unix philosophy.
- Events are set up to trigger your functions. On AWS, these events include infrastructure events such as an AWS API Gateway HTTP endpoint request (useful for HTTP APIs) and an AWS S3 bucket upload (useful for file uploads).
- Resources are infrastructure components which your Functions communicate with. Because functions are stateless, we need some way to capture and store state (in an AWS DynamoDB table or an AWS S3 bucket for example.)
Next, let’s look at the createCharge
function. This is the function that takes in a Stripe token and uses it to create a Stripe charge:
An AWS Lambda (Node.js) handler function takes takes three arguments:
event
– AWS Lambda uses this parameter to pass in event data to the handler.context
– AWS Lambda uses this parameter to provide your handler the runtime information of the Lambda function that is executing.callback
– You can use the optional callback to return information to the caller, otherwise return value is null.
In the createCharge
function, we retrieve the payment details from the HTTP request body and call Stripe’s API to process the charge. We then return an HTTP response containing the created charge object.
Deployment
To deploy our serverless
application to AWS, do:
The serverless
CLI will translate serverless.yml
into a provider specific language such as AWS CloudFormation and set up your cloud infrastructure.
Since we’ve specified an HTTP event trigger for our createCharge
function in serverless.yml
, we get a URL endpoint https://kpygs0yhak.execute-api.ap-southeast-1.amazonaws.com/dev/charges
we can use to trigger our function. Behind the scenes, serverless
created an AWS API Gateway resource and a mapping between our HTTP route and lambda function. This is the backend url that our frontend application communicates with.
Testing
Since each our functions only does one thing, it’s a unit and by definition unit testable! Check out createCharge.test.js
:
We use the Jest test framework, lambda-tester to invoke our functions locally, and nock to stub external APIs. We use Jest snapshots to simplify the process of generating test cases.
Summary
Congratulations! You’ve gone serverless!
We’ve built a scalable payments system by leveraging an external compute service and third-party APIs. Along the way, we learned:
- What serverless is about, and why it’s compelling
- How a payment flow works with Stripe on both frontend and backend
- The basic abstractions of serverless: Events, Functions, Resources
- How to create a Serverless backend with Node.js and AWS Lambda
- How to set up event triggers for functions
- How to deploy functions
- How to write and run unit tests
Thank you for reading!
Source Code
Feel free to clone and check out the source code:
Pull requests and feedback are most welcome.
Published at DZone with permission of Yos Riady, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments