This gem is under heavy development and is not ready to be used in product systems.

Cathode

Cathode is a gem for Rails projects that generates API boilerplate for REST applications.

Features

  • Automatically generate endpoints (routes + controllers) for common RESTful actions:
    • Listing resources, optionally filtered and paginated
    • Finding a single resource
    • Creating a new resource
    • Updating a resource
    • Deleting a resource
  • Endpoints respond to JSON and output JSON by default (possibly add XML et al later on?)
  • Versioning of endpoints
  • Deprecation
  • Auto-documentation

Getting Started

To generate the api directory and mount the engine:

rails generate cool

Note: Your API can be defined using the resource method in your api/api.rb file, using separate files and the Cathode::API class, or a combination of both. For brevity, this document uses resource with the assumption that everything is in api.rb. See the section below, “Files & Naming Conventions,” for details on using the other method.

In the simplest case, you can use only default actions:

resource :products, actions: [:index, :show, :search]

Contrary to Rails’s routes.rb file–in which the default actions are included unless explicitly excluded–only actions that you specify are defined. Out of the box, the actions available are: :index, :show, :create, :update, :delete, :search.

In this case, the following routes are created: get api/products/, get api/products/{id}, and get api/products/search. By default, all products will be returned in the index call, and no permissions will be enforced on the show call. By default, the search call will take a query parameter and search for it using the Product.title field.

Serialization

Cathode doesn’t do any explicit serialization of resources when responding to requests. However, it does use render: json, which will invoke ActiveModel serializers if you’ve defined them.

Versioning

Versioning is encouraged to prevent you from introducing breaking API changes. Your API’s versions should use Semantic Versioning, which enables Cathode to deduce patches, non-breaking changes, and breaking changes. Cathode also makes it easy to deprecate all or part of any version of your API at any time.

If you define your resources without any versions, Cathode assumes it’s version 1.0.0 of your API. When you’re ready to introduce changes, you can easily provision a new version:

resource :products, actions: [:index, :show, :search]

version 1.1 do
  resource :sales, actions: [:all]
  # the products resource is inherited from version 1
end

version 2 do
  # the products resource is inherited from version 1.1, except we explicitly
  # remove the `search` action
  resource :products
    remove_action :search
  end
end

Versions inherit from their ancestors, so anything not explicitly changed in version 2 will be carried over from version 1.1, which in turn inherits from version 1.

In version 1.1, we’ve added a new sales endpoint. This doesn’t introduce a breaking change, as users of version 1.0 can still use it without knowing about the sales endpoint.

However, in version 2 we do introduce a breaking change–namely, that products can no longer be searched. Users of versions 1.x of our API will still be able to access the endpoint, but users of version 2 will not.

Usually, changes like these would require the addition of new route namespaces and groups of controllers. With Cathode, these are all taken care of for you.

Goodies on the index action

By default index actions return all records in your resource’s default scope. However, common operations–like filtering, sorting, pagination, cursoring, etc–are also supported. For example, an application might make the following API call:

GET /api/products?query=flashlight&sort=desc&page=5

To add support for this functionality in Cathode, just flip on querying, sorting, and paging in the index action:

resource :products do
  action :index do
    allows :querying, :sorting, :paging
  end
end

Params

All actions have access to the request params hash.

Custom action behavior

Of course, you won’t want to use Cathode’s default actions in every scenario.

version 2.1 do
  resource :sales, actions: [:all] do
    action :show do
      change 'Checks user permission'
      access_filter do |current_user|
        resource.user == current_user
      end
    end
  end
end

In this case, we need to prevent users from seeing sales that aren’t theirs. Happily, Cathode provides some neat shorthands for common scenarios like this. access_filter can be applied to any action, and should be a method that returns true if the user can access the resource and false if not. If the user cannot access the resource, a 401 Unauthorized header will be sent.

In those cases where you want to do all of the logic yourself, and just want the endpoints that Cathode generates, you can override an action entirely:

resource :sales, actions: [:all] do
  # show a random sale instead
  override_action :show do
    render json: Sale.sample
  end
end

Deprecation

With Cathode’s slick versioning, you’ll be implicitly deprecating junk in previous versions each time you introduce a new breaking change. When that happens, users of previous versions of your API should be told that a feature they’re using is deprecated. By default, Cathode will respond with a deprecation warning for those users. So users of version 1.1 of your API would receive the following response when making a call to /api/products/search:

{
  "products": [ array of the products found… ]
  "messages": [
    "The search endpoint is deprecated and is removed in version 2.0.0 of the
API"]
}

Files & Naming Conventions

While this example has been putting all actions in a single file, in reality you’ll probably want to specify individual files for each resource. You can use the same versioning scheme in those files; as long as your resource APIs inherit from Cathode::API, Cathode will match up everything accordingly:

# app/api/products_api.rb

class ProductsAPI < Cathode::API
  actions: [:index, :show, :search] # version 1.0.0 is implied

  version 2 do
    remove_action :search
  end
end

Since nothing about products changed in version 1.2 (which only added sales, above), it will use the same actions as it did in version 1. In version 2, everything is carried over except for the search endpoint.

Documentation & Changelogs

By sticking to Cathode’s versioning scheme, you tell it a lot about your API. So much, in fact, that we can use it to automatically generate documentation for all versions of your API and generate a changelog. Running cool docs will generate the documentation at docs/api/1.0.0, docs/api/1.1.0, docs/api/2.0.0, and docs/api/2.1.0. It will also automatically add a Changelog:

# Changelog
## Version 2.1.0
Checks user permission in `sales#show`.

## Version 2.0.0
Removes the `search` endpoint from `products` resource.

## Version 1.1.0
Adds `sales` resource with the following endpoints:
- `GET /api/sales`
- `GET /api/sales/{id}`
- `GET /api/sales/search`
- `POST /api/sales`
- `PUT /api/sales/{id}`
- `DELETE /api/sales/{id}`

## Version 1.0.0
Initial release

Adds `products` resource with the following endpoints:
- `GET /api/products`
- `GET /api/products/{id}`
- `GET /api/products/search`
- `POST /api/products`
- `PUT /api/products/{id}`
- `DELETE /api/products/{id}`