How Rubycoders uses Stripe webhooks

Cristiano - 2017-05-03

Rubycoders uses Stripe system in order to receive payments via credit card.

Wikipedia says:

Stripe is a US technology company, operating in over 25 countries, that allows both private individuals and businesses to accept payments over the Internet. Stripe focuses on providing the technical, fraud prevention, and banking infrastructure required to operate on-line payment systems.

Rubycoders never keeps the credit card information in its local database. Therefore, it increases its security.
Stripe has a very powerful event system:

Whenever something interesting happens (like a new charge succeeding or failing, a customer changing their subscription, or an invoice being created), Stripe creates an event.

An Event has some properties. Among them, the type property is very important because it identifies what happened in Stripe.
For example:

type: "customer_subscription.created"

As soon as Stripe creates an event, it sends an HTTP POST request to a specific configured url which has been set consequently.

Once Rubycoders receives the request from Stripe, it analyzes it and then it launches the correct routine in order to manage the event.

For example, if the event is a customer_subscription.created, Rubycoders sends an email to the customer making him aware of the successful subscription creation.

Stripe includes several types of events but Rubycoders is interested only in a couple of them. Indeed, we want to instantiate the correct routine for each event we would like to manage.

First of all, you have to set up the router in order to receive the http post request

#config/routes.rb
resources :hooks, only: :create

then, set up the create action in HooksController:

#app/controllers/hooks_controller.rb

class HooksController < ApplicationController

  def create
    event_manager = EventManager.new Event.retrieve(params[:id])
    event_manager.manage
    render nothing: true, status: 201
    rescue StripeError
      render nothing: true, status: 400
  end
end

The http post request contains the id of the event. For that reason, we can recover the event through the retrive method, offered by the Event class which is here mentioned stripe-ruby gem

The EventManager class is the core system. It is a simple Ruby PORO class which analyzes the incoming event and instantiates the correct corrisponding class.

Finally, in case everything was successfully done, the controller will answer with a 201 http code. Otherwise, the controller will answer with 400.

This is the EventManager class

#lib/event_manager.rb
class EventManager

  attr_reader :event, :method, :clazz

  def initialize event
    @event = event
    @method = event.type.split(".").last.to_sym
    @clazz = event.type.split(".").tap(&:pop).map(&:capitalize).join
  end

  def manage
    clazz_istance.new(event).send method
  end

  private
  def clazz_istance
    clazz.constantize
  end
end

If the event type is:

type: "customer_subscription.created"

Then, we will have a class named customer_subscription.rb which will contain the method created.

The EventManager class instantiates dynamically the correct class analyzing the event type.

For example, the customer_subscription.created event has the corresponding class and method

#lib/customer_subscription.rb
class CustomerSubscription
  attr_reader :event

  def initialize event
    @event = event
  end

  def created  
      #your logic here
      #for example you can send an email to customer
  end
end

Wrapping up

In this post only the basic system has been explained in order to make it as clear as possible. For that reason, the management of the exceptions was ignored. However, if there is an incoming event with any Ruby PORO class, the system will offer an exception to be managed.

It should be important to put PORO classes inside a namespace, like StripeEventManager or similar ones.

Bonus
To improve the security, it is better to accept the http requests only coming from Stripe web hooks domain.