A hands-on information on Stripe’s Product API Integration

Getting Began
Stripe APIs have superb options for e-commerces and marketplaces. To make our developer’s life simpler, they provide SDK for some programming languages, together with Ruby.
We are going to begin including the Stripe SDK Gem to our Gemfile.
gem 'stripe'
Don’t neglect to run
bundle set up
in your terminal after that.
Now you will want to create a stripe initializer file in your utility. For that, run the command beneath in your terminal:
contact config/initializers/stripe.rb
Then, open the stripe.rb
file and write the content material beneath:
Stripe.api_key = Rails.utility.credentials.stripe_secret_key
We didn’t add that Stripe’s Secret Key in our credential file, so let’s do that.
To open your credential file, run in your terminal:
EDITOR=nano rails credentials:edit
Get your Stripe Secret Key here.
Your credential file should appear like this:
# aws:
# access_key_id: 123
# secret_access_key: 345
# Used as the bottom secret for all MessageVerifiers in Rails, together with the one defending cookies.secret_key_base: [YOUR SECRET KEY BASE]
stripe_secret_key: [YOUR SECRET KEY HERE]
Notice that the
secret_key_base
is autogenerated, you don’t have to edit.
The Product Logic
This part is concerning the product logic on our facet, our API. It would include two fashions: Product and Worth.

Our Product Mannequin may have as many Costs associated as the appliance want. However why?
Let’s assume one in all your merchandise is an iPhone 13. As it’s possible you’ll know, the iPhone 13 has a bunch of variants, together with totally different colours and storage. We need to create a single Product file that represents the iPhone, and a Worth file for every coloration variant.
The Product Code
Now we’ll code the Product primarily based on the logic we noticed above.
Run in your terminal:
rails g mannequin Product identify description:textual content stripe_id
Take a more in-depth take a look at the Product attributes:
identify
can be a string that represents the identify of the product;description
can be a string that represents a brief textual content, describing the product;stripe_id
can be a string that represents a reference to our Product within the Stripe API.
Now, run:
rails g mannequin Worth title particulars:textual content amount_cents:integer product:references stripe_id
Taking a more in-depth look to the Worth attributes:
title
can be a string that represents the variant of the product we’re promoting, it could possibly be “Inexperienced” for instance;particulars
can be a string that represents a brief textual content, describing the product variant;amount_cents
can be an integer that represents the worth of the product in cents.product_id
can be an integer that represents a reference to a Product.stripe_id
can be a string that represents a reference to our Worth within the Stripe API.
The Product Mannequin:
class Product < ApplicationRecord
validates :identify, :stripe_id, presence: true, allow_blank: false
validates :stripe_id, uniqueness: true has_many :costs, dependent: :destroy accepts_nested_attributes_for :costs before_validation :create_stripe_reference, on: :create
after_update :update_stripe_reference def create_stripe_reference
response = Stripe::Product.create( identify: identify )
self.stripe_id = response.id
finish def retrieve_stripe_reference
Stripe::Product.retrieve(stripe_id)
finish def update_stripe_reference
Stripe::Product.replace(stripe_id, identify: identify )
finish
finish
- Validation to be sure that
identify
andstripe_id
attributes can be at all times current. - Validation to be sure that
stripe_id
can be distinctive within the database. - Setup for accepting nested attributes by way of the product JSON object on creating the endpoint.
- Has Many associations with costs.
- The “after” callbacks can be triggered when one of many file dealing with actions known as. That is essential to maintain our stripe information updated with our database.
The Worth Mannequin
class Worth < ApplicationRecord
validates :title, :amount_cents, :stripe_id, presence: true, allow_blank: false
validates :stripe_id, uniqueness: true belongs_to :product before_validation :create_stripe_reference, on: :create
after_update :update_stripe_reference def create_stripe_reference
response = Stripe::Worth.create(
unit_amount: amount_cents,
forex: 'usd',
product: product.stripe_id,
)
self.stripe_id = response.id
finish def retrieve_stripe_reference
Stripe::Worth.retrieve(stripe_id)
finish def update_stripe_reference
response = Stripe::Worth.create(
unit_amount: amount_cents,
forex: 'usd',
product: product.stripe_id,
)
self.stripe_id = response.id
finish
finish
- Validation to be sure that title, stripe_id and amount_cents attributes can be at all times current.
- Belongs To affiliation with a product.
- The “after” callbacks that can be triggered when one of many file dealing with actions be referred to as. That is essential to maintain our stripe information updated with our database.
The Merchandise Controller
By means of this step we’ll create a controller for merchandise. The actions can be a easy CRUD.
Run in your terminal:
rails g controller Api::V1::Merchandise index present create replace destroy
With the controller created you will want to edit it and make it appear like this:
module Api
module V1
class ProductsController < ApplicationController
before_action :set_product, solely: %i[show update destroy] def index
@merchandise = Product.consists of(:costs).all render json: @merchandise, embody: %i[prices], standing: :okay
finish def present
render json: @product, embody: %i[prices], standing: :okay
finish def create
@product = Product.new(product_params) if @product.save
render json: @product, standing: :okay
else
render json: @product.errors, standing: :unprocessable_entity
finish
finish def replace
if @product.replace(product_params)
render json: @product, standing: :okay
else
render json: @product.errors, standing: :unprocessable_entity
finish
finish def destroy
@product.destroy head :no_content
finish personal def set_product
@product = Product.consists of(:costs).discover(params[:id])
finish def product_params
params.require(:product).allow(:identify, :description, prices_attributes: %i[title details amount_cents])
finish
finish
finish
finish
I cannot describe this controller code as soon as I think about you in all probability already know the logic of a Rails Controller. In case you are not familiarized I encourage you to take a learn on this article.
The Costs Controller
By means of this step we’ll create a controller for costs. The actions can be a easy CRUD.
rails g controller Api::V1::Costs index present create replace destroy
With the controller created you will want to edit it and make it appear like this:
module Api
module V1
class PricesController < ApplicationController
before_action :set_product, solely: %i[index create]
before_action :set_price, solely: %i[show update destroy] def index
@prices = @product.costs render json: @prices, standing: :okay
finish def present
render json: @price, standing: :okay
finish def create
@price = Worth.new(price_params.merge(product_id: @product.id)) if @price.save
render json: @price, standing: :okay
else
render json: @price.errors, standing: :unprocessable_entity
finish
finish def replace
if @price.replace(price_params)
render json: @price, standing: :okay
else
render json: @price.errors, standing: :unprocessable_entity
finish
finish def destroy
@price.destroy head :no_content
finish personal def set_product
@product = Product.discover(params[:product_id])
finish def set_price
@price = Worth.discover(params[:id])
finish def price_params
params.require(:worth).allow(:title, :particulars, :amount_cents)
finish
finish
finish
finish
Our controllers look superior!!
The Routes
We must edit our routes.rb file now.
It should appear like this:
Rails.utility.routes.draw do
namespace :api do
namespace :v1 do
assets :merchandise, besides: %i[new edit] do
assets :costs, solely: %i[index create]
finish assets :costs, solely: %i[show update destroy]
finish
finish
finish
Principally, we’re organising CRUD routes for merchandise and costs, however the worth routes can be underneath a product namespace. That signifies that the format for costs endpoint can be at all times:
/api/v1/merchandise/:product_id/costs
Testing our API on a HTTP Shopper
To check our API we have to increase our server, run in your terminal:
rails s
Creating Product
Methodology: POST | URL: http://localhost:3000/api/v1/merchandise
Headers: “Content material-Sort”: “utility/json”
"product":
"identify": "iPhone 13 Mini",
"description": "Our most superior twin‑digicam system ever.",
"prices_attributes": [
"title": "Green - 128GB",
"details": "New Green Finish",
"amount_cents": 79900
,
"title": "Green - 256GB",
"details": "New Green Finish",
"amount_cents": 89900
]
Updating Product
Methodology: PUT | URL: http://localhost:3000/api/v1/merchandise/1
"product":
"identify": "iPhone 13"
Itemizing All Merchandise
Methodology: GET | URL: http://localhost:3000/api/v1/merchandise
Retrieving Product
Methodology: GET | URL: http://localhost:3000/api/v1/merchandise/1
Destroying Product
Methodology: DELETE | URL: http://localhost:3000/api/v1/merchandise/1
Creating Worth (for an present product)
Methodology: POST | URL: http://localhost:3000/api/v1/merchandise/1/costs
Headers: “Content material-Sort”: “utility/json”
"worth":
"title": "Black - 128GB",
"particulars": "New Inexperienced End",
"amount_cents": 69900
Updating Worth
Methodology: PUT | URL: http://localhost:3000/api/v1/costs/1
Headers: “Content material-Sort”: “utility/json”
"worth":
"amount_cents": 59900
Retrieving Worth
Methodology: GET | URL: http://localhost:3000/api/v1/costs/1
Destroying Worth
Methodology: DELETE | URL: http://localhost:3000/api/v1/costs/1
Stripe make the mixing with their API fairly easy and simple with the SDK.
There are a whole lot of assets on Stripe API that weren’t explored throughout this text. I imply to publish different ones sooner or later, associated to costs cost intent, and webhooks.
You may check the complete Stripe Docs here.
Need to Join?If in case you have any questions or solutions, text me on Twitter