-
After cloning this repo, run:
npm install
- Add a .env file with your Stripe API secret key, there's a
.env.example
file for you to refer to. Feel free to change that file name to.env
and add your Stripe API secret key there.
npm start
- Add a .env file with your Stripe API secret key, there's a
-
Click on one of the "Purchase" buttons under the books and it should take you to the checkout page. Fill in the inputs, make sure you have a valid email ([email protected]). Fill in the card info with
4242424242424242
and hit Enter or click "Pay". You should see the success screen with some details of your purchase going through.
The goal of this challenge was to create a simple e-commerce flow of fulfilling a purchase, using Stripe Elements and displaying the charge ID and total amount after.
-
My solution uses Stripe Elements for collecting card data from a users input, and creates a
Charge
using that token for Stripe'sCharge
API. The Card information the user input on the form is used to create atoken
. Thattoken
is passed to an express backend, where we use thecreate Charge
API to fulfil theCharge
. We use Stripe Elements because it's a safe and secure way for buyers to input their credit card information while also saving tons of work for the developer. -
For the most part, I was able to use a lot of the code from the examples provided on the Stripe website. More specifically the
Accept a Card Payment
walk through (linked below this paragraph). There's a list of things I'd like to bring attention to that helped me get to my solution:
- Added shipping inputs to the form since the user is purchasing physical books
- Added an
itemId
value to/checkout
get request, that way I could pass it as a query param to the server. - I created a map called
ITEM_DATA
to refer to the selected products viaitemId
(which gets passed as a query param). - I created a function for formatting the data to display with proper currency format on the backend before returning it.
var formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
});
Usage:
formatter.format(result.amount / 100)
For example: ITEM_DATA[3]
refers to the data associated with the Working In Public Book.
This way I was able to dynamically access the appropriate data per item.
- The success page has the title of the book,
Charge
id, and the amount as well as a URL to see more details about the purchase.
It's pretty weird navigating basic HTML/CSS/JS and an express server after living life on the cutting edge for 2-3 years straight. Fortunately, I used to teach these kind of implementations at Resilient Coders so it wasn't so bad. One cool thing that I learned is that body-parser is deprecated and express has something for encoding urls now.
Another challenge was figuring out the best way to dynamically send the token info to the Charge API. My initial idea was to create another hidden input on the client side with information on each product and sending the whole thing through req.body
, but it didn't feel right. I saw that in the set up of this project, each product was referred to in the switch statement by numbers 1-3, so I figured that'd be a great opportunity to use that number and refer to an object on the server side. This is much more secure approach anyway, since no one can pass any fake values to the server this way.
Links that helped me get to the solution: Stripe Charge API Docs
Accept a Card Payment walk-through is where I learned to use Stripe Elements.
- As far as extending this, I definitely would have preferred seeing this in React, with Gatsby or Next JS and serverless functions to take care of handling the tokens and Charge API securely. That isn't exactly extending the current application, though. If I were to entertain the idea of staying on this HTML/CSS/Node set up only, I would handle getting the products differently.
I'd migrate to the Payments API. Instead of using the server to process charges, we'd use it to set up Payment Intents. The Charge API is deprecated and limited anyway, so switching to the Payments API is recommended. It would look similar to the way Charges are made:
const paymentIntents = await stripe.paymentIntents.create({
amount,
currency: "usd",
});
Depending on who I'm talking to, I might suggest using Stripe Checkout (very unlikely since the in-house card collection is usually the preferred experience) but I would recommend this to anyone who might not want to manage their own server or the payment process itself and they could create products using the Product and Price APIs.
Another thing that might be considering more "robust" is manage error handling. Right now, if you submit an e-mail with an invalid email format, you get an error but you don't get a nice page that lets you know there was an error.