restable

A toolkit for rapidly building REST APIs with Rails.

MIT License

Downloads
428
Stars
3

Restable

Building a REST API — even with Rails — is tedious work. This project aims to eliminate all that tedious work by providing the generic boilerplate functionality that all APIs require so that you can start building out your custom business logic right away. Some aspects of building a REST API in Rails are trivial, in which case guidance on best practices will be provided. Think of Restable as a combination of open-source code and tutorials.

This project is highly inspired by ideas and concepts found in the Stripe API and Shopify API, and aims to allow you to build APIs of similar quality with as little work as possible.

Building Blocks

Rather that lock you into using a custom DSL or particular architecture, RestEasy will expose opt-in functionality through concerns, helpers, etc. and suggest patterns for organizing your code. Think of RestEasy as a tiny framework for building REST APIs rather than a drop-in, pre-packaged solution.

Planned Features

  • Management of API Secrets & generating secure token
  • Authentication with basic and bearer token
  • Consistent error handling
  • JSON Serialization of API resources using JBuilder
  • Versioning encouraged through convention over configuration

Potential Future Features

  • Pagination with Kaminari
  • Webhook delivery to Endpoints
  • Generators for quickly scaffolding a new API resource
  • RSpec helpers for testing your API
  • Request logging
  • Expanding responses
  • Request IDs and logging
  • Rate limiting
  • Admin monitoring dashboard
  • Documentation generator

Usage

API Credentials

One of the first things you need to do when developing a REST API is create a model to represent authentication credentials. Rails has an excellent has_secure_token module that handles creation of (surprise!) secure tokens. Restable includes a Restable::SecureToken concern that can be included into your model that provides some additional functionality, like presence and uniqueness validation of the token attribute.

We're going to call our credential model Api::SecretKey. Let's imagine our app has an Account model, and an account can have many secret keys. Let's generate the model:

rails generate model api/secret_key token:token account:references

👉 Tip: If you want to use the Restable::SecureToken concern, your token column must be named token.

The command above will generate app/models/api/secret_key.rb and the associated migration. Rails will add a unique index on token to the migration, but it's a good idea to also add a null: false constraint to that column:

diff --git create_api_secret_keys.rb create_api_secret_keys.rb
index 32c4a68..0b1702e 100644
--- create_api_secret_keys.rb
+++ create_api_secret_keys.rb
@@ -1,11 +1,11 @@
 class CreateApiSecretKeys < ActiveRecord::Migration[7.0]
   def change
     create_table :api_secret_keys do |t|
-      t.string :token
+      t.string :token, null: false
       t.references :account, null: false, foreign_key: true

       t.timestamps
     end
     add_index :api_secret_keys, :token, unique: true
   end
 end

The model file generated by Rails will already include has_secure_token. You can remove this and include Restable::SecureToken if you like:

# app/models/api/secret_key.rb
class Api::SecretKey < ApplicationRecord
  include Restable::SecureToken

  belongs_to :account
end

and add the has_many to your Account model:

# app/models/account.rb
class Account < ApplicationRecord
  has_many :api_secret_keys, dependent: :delete_all, class_name: "Api::SecretKey"
end

Run db:migrate and your credential system should be ready to go:

account = Account.first
secret_key = account.api_secret_keys.create!
# => <Api::SecretKey:0x00000001077190f0 id: 13, token: "[FILTERED]", account_id: 2, created_at: Fri, 14 Jul 2023 16:44:52.462608000 UTC +00:00, updated_at: Fri, 14 Jul 2023 16:44:52.462608000 UTC +00:00>
secret_key.token
# => "api_secret_key_yLt4AM6S9RQK9Y1C6kYvJZ8w"

Someting to notice is the "api_secret_key" token prefix. Restable::SecureToken automatically adds this prefix by singularizing the table name. You can change the prefix by overriding the secure_token_prefix class method:

class Api::SecretKey < ApplicationRecord
  include Restable::SecureToken

  def self.secure_token_prefix
    # Generate tokens in the format "secret_key_yLt4AM6S9RQK9Y1C6kYvJZ8w"
    "secret_key"
  end
end

You can disable the prefix by having secure_token_prefix return nil.

Of course, because Api::SecretKey is just a normal Rails model, you can add whatever additional functionality you want to it, like an expires_at timestamp, a created_by attribute to track the user who generated the toke, etc. Or maybe your Account model should only have a single secret key, in which case you can specify has_one :api_secret_key instead of has_many :api_secret_keys.

You can also create as many credential model types as you need. For example, if you want to dispatch signed webhooks you could create a Webhook::Signature model using the same Restable::SecureToken approach.

Installation

Add this line to your application's Gemfile:

gem "restable"

And then execute:

$ bundle

Or install it yourself as:

$ gem install restable

Contributing

Contributions are welcome.

License

The gem is available as open source under the terms of the MIT License.