Type to search documentation...

Separate Doc Files

Keep controllers clean by defining documentation in dedicated modules. This is the recommended approach for larger APIs.

Creating a doc file

Create a module in app/docs/ that extends Docit::DocFile:

# app/docs/api/v1/users_docs.rb
module Api::V1::UsersDocs
  extend Docit::DocFile

  doc :index do
    summary "List all users"
    description "Returns a paginated list of users"
    tags "Users"

    parameter :page, location: :query, type: :integer,
              description: "Page number"

    response 200, "Users retrieved" do
      property :users, type: :array, items: :object do
        property :id, type: :integer, example: 1
        property :email, type: :string, example: "user@example.com"
      end
      property :total, type: :integer, example: 42
    end
  end

  doc :create do
    summary "Create a user"
    tags "Users"

    request_body required: true do
      property :email, type: :string, required: true
      property :password, type: :string, required: true, format: :password
    end

    response 201, "User created" do
      property :id, type: :integer
    end

    response 422, "Validation failed" do
      property :errors, type: :object do
        property :email, type: :array, items: :string
      end
    end
  end

  doc :show do
    summary "Get a user"
    tags "Users"

    parameter :id, location: :path, type: :integer,
              required: true, description: "User ID"

    response 200, "User found" do
      property :id, type: :integer, example: 1
      property :email, type: :string
      property :name, type: :string
    end

    response 404, "User not found" do
      property :error, type: :string, example: "Not found"
    end
  end
end

Wiring to a controller

Use use_docs in your controller to load all docs from a module:

# app/controllers/api/v1/users_controller.rb
class Api::V1::UsersController < ApplicationController
  use_docs Api::V1::UsersDocs

  def index
    # pure business logic
  end

  def create
    # pure business logic
  end

  def show
    # pure business logic
  end
end

That's it. The controller stays clean and focused on business logic.

File naming convention

Doc files should mirror the controller namespace:

Controller Doc file
Api::V1::UsersController app/docs/api/v1/users_docs.rb
Api::V1::Auth::SessionsController app/docs/api/v1/auth/sessions_docs.rb
Api::V2::ProductsController app/docs/api/v2/products_docs.rb

Note on doc vs doc_for

Inside doc files you use doc :action_name (without the _for suffix). Inside controllers you use doc_for :action_name. The DSL inside the block is identical.

When to use separate doc files

  • APIs with many endpoints per controller
  • Teams where backend and API-docs writers are different people
  • When you want controllers to contain only business logic
  • Complex request/response schemas that would clutter the controller