0.0
The project is in a healthy, maintained state
A generic interface and abstraction layer for dealing with third-party data providers and APIs in Rails. ProviderKit helps you to add a layer between your third-party APIs and internal code.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

Runtime

~> 8.0
~> 2.2
 Project Readme

ProviderKit

ProviderKit is a simple utility for creating an abstraction layer between various third-party services (usually via API) and your application's code.

It contains some conventions and utilities for making this easier. Think of it as a way to create simple wrappers on top of third-party APIs, but also a way to make those consistent across 'providers' of the same type.

For example, say you support payments from multiple third-party services like Stripe or PayPal. In each of those services we'll need to handle customers, subscriptions, and payments. Here's how we could interface with that using ProviderKit:

# customer 1 uses Stripe
user = User.create(provider: :stripe, ...)
user.provider.customers.get(id: user.customer_key) # => { id: "cus_Nff" }

# customer 2 uses PayPal
user2 = User.create(provider: :paypal)
user.provider.customers.get(id: user.customer_key) # => { id: "abc-123" }

Then anywhere in your code where you have business logic that requires a customer the code is consistent, but each individual provider contains its custom code to deal with that provider's details. Here's what the 'get customer' logic could look like inside of a provider's configuration:

module StripeProvider
  class Customers
    def get(id:)
      stripe_customer = Stripe::Customer.retrieve(id)

      {
        id: stripe_customer.id,
        # ... etc
      }
    end
  end
end

This library was originally developed for this exact use case, but we use it for a bunch of different provider types including linking multiple CRM tools, ecommerce providers, and many more.

Generator

Use the generator to create a new provider:

rails g provider my_provider_name

Capabilities

Providers have 'capabilities' to determine what types of things they can do. Each provider registers those capabilities within the provider setup itself. For example, the Customers class above would likely be registered within the StripeProvider like this:

module StripeProvider
  class Provider

    include ProviderKit::Capable

    capable_of :subscriptions, with: Customers

  end
end

This registration offers some nice reflection methods, so you can determine at runtime which features a particular provider allows. For example, Stripe has a customers search endpoint but PayPal does not. So we can build the search feature into StripeProvider:

module StripeProvider
  class Customers
    def search(query:)
      customers = Stripe::Customer.search(query:)

      customers.map do |customer|
        {
          id: customer.id,
          name: customer.name,
          # ...
        }
      end
    end
  end
end

Then we can check it at runtime to make sure the provider is capable of this action:

if user.provider.capable_of?(:customers, :search)
  user.customers.search(query: 'john@example.com')
else
  []
end

This is a primitive example but it's a powerful concept!

Credentials

Rails credentials can be used within the context of a provider's capability methods. By convention, store each provider's credentials in this format:

# rails credentials:edit

providers:
  provider_name_here:
    secret_key: abc123

  stripe:
    secret_key: sk_1234

Then they can be used anywhere in a provider:

module StripeProvider
  class Customers
    def get(id:)
      # you probably should put this in an initializer instead
      # so it doesn't need to be in every method,
      # but it does work!
      Stripe.api_key = credentials.secret_key

      # ...
    end
  end
end

A Work In Progress

This gem has been in production since 2019, so it's battle tested, but not very well spec-tested. It's an ongoing work in progress. If you find it helpful, go for it, I'm very open to contributions. But it's presented as-is, and probably won't be very actively maintained other than ensuring it works with new versions of Ruby and Rails.