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