API with NestJS #36. Introduction to Stripe with React

JavaScript NestJS TypeScript

This entry is part 36 of 42 in the API with NestJS

Nowadays, a lot of web applications accept online payments. Although this is not straightforward to implement, there are some ready-to-use solutions that we can take advantage of. In this article, we look into Stripe. It serves as a payment processing platform that does the heavy lifting for us. To implement it, we use NestJS and React.

Getting up and running with Stripe

To start using Stripe, we first need to sign up. After verifying our email address, we can go straight to the API keys page.

On the above page, there are two important things. The first of them is the publishable key. We use it on the frontend part of our application. We can safely expose it in our JavaScript code.

The second one is the secret key. We keep it on the backend side and use it to perform API requests to Stripe. It can be used to create charges or perform refunds, for example. Therefore, we need to keep it confidential.

As a best practice, we make sure not to commit neither of the above keys to the repository. We keep them in the environment variables.

If we want to start accepting real payments with Stripe, we need to activate our account. To do that, we need to answer some questions about our business and provide bank details. Since this is optional for development and testing purposes, we can skip it for now.

Using Stripe with NestJS

If we would intend only to have simple one-time payments, we could use the prebuilt checkout page. In the upcoming articles, we want to implement features such as saving credit cards for later use. Therefore, we implement a simple custom payment flow:

  1. A user creates an account through our NestJS API. Under the hood, we create a Stripe customer for the user and save the id for later.
  2. The user provides the details of the credit card through the React application. We send it straight to the Stripe API.
  3. Stripe API responds with a payment method id. Our frontend app sends it to our NestJS API.
  4. Our NestJS API gets the request and charges the user using the Stripe API.

There are various ways to integrate NestJS and Stripe. Although there are some ready-to-use libraries, they don’t have many weekly downloads. Therefore, in this article, we implement Stripe into our NestJS application ourselves. Fortunately, this is a straightforward process.

Let’s start by adding some environment variables we will need.

app.module.ts

.env

The is the secret key we copied from our Stripe dashboard. Although we could support payments in various currencies, we store the currency in the variable in this simple example.

We want our React application to send authenticated requests to our API. Therefore, we need to set up Cross-Origin Resource Sharing.

If you want to know more about CORS, check out Cross-Origin Resource Sharing. Avoiding Access-Control-Allow-Origin CORS error

main.ts

Setting up Stripe

We don’t have to make requests to the Stripe API manually. There is a library that can do that for us.

We need to provide the above package with the secret Stripe key. To do that, let’s create a service.

stripe.service.ts

Above, we use the variable we’ve defined before. We also need to define the version of the Stripe API.

Stripe sometimes makes changes to their API that isn’t backward-compatible. To avoid issues, we can define the version of the API we want to use. At the time of writing this article, the current API version is .

If you want to know more about the changes to the API, check out the API changelog

Creating a customer

In our application, we want only the authenticated users to be able to make payments. Because of that, we can create a Stripe customer for each of our users. To do that, let’s add the method to our .

stripe.service.ts

The function calls the Stripe API and returns the data bout the Stripe customer. We need to save it in our database. To do able to do that, let’s modify our .

user.entity.ts

Now, we can use all of the above in the :

users.service.ts

If you want to know more about authentication, check out API with NestJS #3. Authenticating users with bcrypt, Passport, JWT, and cookies

In the upcoming articles in this series, we’ll be able to use the to, for example, save credit cards for the user and retrieve them.

Charging the user

The last part of our NestJS API is the logic for charging the user. Let’s start with adding the method to our :

stripe.service.ts

There a few important things happening above:

  • the is an id sent by our frontend app after saving the credit card details,
  • the is the Stripe customer id of a user that is making the payment,
  • the flag is set to true to indicate that we want to confirm the payment immediately.

Instead of setting the flag to true, we can also confirm the payment separately.

To use the above logic, let’s create the :

charge.controller.ts

createCharge.dto.ts

Using Stripe with React

To take advantage of all of the backend code we wrote above, we need a React application. In this article, we are using Create React App with TypeScript.

In this article, we assume that the user is already authenticated. If you want to know more about authenticating with JWT, check out API with NestJS #3. Authenticating users with bcrypt, Passport, JWT, and cookies

The first step to do is to add the Stripe publishable key to environment variables. While we’re on it, we also add the and the variable.

Make sure not to confuse the publishable key with the secret key.

All custom environment variables need to start with when using Create React App.

Now, we need to install some Stripe-related dependencies.

To integrate Stripe with React, we need to start with providing the publishable key.

App.tsx

Above, you can see that we use the component. Let’s create it:

PaymentForm/index.tsx

I like to keep my template separate from the logic to maintain the separation of concerns. If you want to know more, check out JavaScript design patterns #3. The Facade pattern and applying it to React Hooks

A significant thing to consider is that the Stripe library renders the credit card form in an iframe.

To access the data provided by the user and send it to the Stripe API, we need the hook provided by Stripe. Let’s use it:

The above code could use some more graceful error handling. We could also add an impoint for the amount to charge. Feel free to implement it.

In our hook, we get the data provided by the user by calling . We then send it to the Stripe API with the method:

In response, Stripe sends us the . We send it to our NestJS API to finalize the payment.

We can now go to the payments dashboard to see that our payment is working as intended.

Above you can see that setting as the amount means 100 cents, not 100 dollars.

Summary

In this article, we’ve learned the basics about Stripe. While doing so, we’ve implemented a simple flow where the user provides the credit card details and makes a payment. This included setting up a Stripe account, implementing a NestJS endpoint to charge the user, and creating a simple React application. There is a lot more about Stripe to learn, so stay tuned!

Series Navigation<< API with NestJS #35. Using server-side sessions instead of JSON Web TokensAPI with NestJS #37. Using Stripe to save credit cards for future use >>
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
audiobookning
audiobookning
1 month ago

Personally, i am not too comfortable on using your workflow of confirming the payment intent on creation. I prefer to do the one easily found on Stripe’s docs:
“…create a PaymentIntent on the server and pass its client secret to the client instead of passing the entire PaymentIntent object. The client confirms the payment, and your server monitors webhooks to detect when the payment successfully completes or fails”.
Although i am sure that that your workflow also has its place, i prefer to, unless there is a strong reason not to do it, to default to the contracted service advice.

Last edited 1 month ago by audiobookning