Bryan Mytko

Software and stuff.

Extracting API Pie

July 17, 2015

Apipie (github) is an amazing Rails engine that lets you document your APIs in the code using Apipie's DSL. It's super simple to set up -- just install the gem and start describing the APIs in your controller:

1
2
3
4
5
6
api :GET, '/posts/:id'
param :id, Integer, required

def show
  #whatever
end

The problem is that once you start adding multiple actions with lots of parameters, things get messy. Your controllers wind up bloating to hundreds of lines, and having all this extra code in there can be extremely distracting. It starts to feel like maybe this code doesn't exactly belong there. Luckily enough, it's easy to extract the Apipie code into its own clean and organized module.

First we can set up a file apipie_descriptions.rb in the /lib directory.

1
2
module ApipieDescriptions
end

Then we can set up files for each of our controllers in the same directory. In this example we'll assume we have APIs for users and posts.

users.rb

1
2
module ApipieDescriptions::Users
end

Then we'll extend ActiveSupport::Concern and include them in the main module as class methods.

1
2
3
4
5
6
7
8
module ApipieDescriptions
  extend ActiveSupport::Concern

  module ClassMethods
    include ClassMethods::Users
    include ClassMethods::Posts
  end
end

We can put all of our Apipie logic in these files now, and simply include this module in our controllers. Note that because of the way the DSL is designed, we need to clear each method when we're done with it so that Apipie knows that we're done defining the documentation for that action.

E.g.,

lib/apipie_descriptions/users.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module ApipieDescriptions::Users
  def apipie_users_index
    api :GET, "/users", "Returns a collection of users"
      description <<-EOS
      If successful, it returns a collection of <tt>users</tt>,
      with status <tt>200</tt>.
    EOS
    apipie_clear(__method__)
  end

  def apipie_users_show
    api :GET, "/users/:id", "Returns a user"
    description <<-EOS
      If successful, it returns a <tt>user</tt>,
      with status <tt>200</tt>.
    EOS
    apipie_clear(__method__)
  end
end

app/controllers/api/v1/users_controller.rb

1
2
3
4
5
6
7
8
module Api::V1
  class UsersController < ApiController
    include ApipieDescriptions

    apipie_users_index
    apipie_users_show
  end
end

And that's all there is to creating well-documented APIs without cluttering up your codebase.