Integrating Stripe’s Product API Into Your Rails API | by Bruno Feres | Apr, 2022

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.

Board with Publish-It

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 and stripe_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

More Posts