Docit
Decorator-style API documentation for Ruby on Rails. Write OpenAPI 3.0.3 docs with clean controller DSL macros, separate doc modules, or AI-assisted scaffolding for undocumented endpoints.
Table Of Contents
- Getting started
- Documentation styles
- Endpoint DSL reference
- AI documentation
- Runtime and development
- Project docs
Installation
Add Docit to your Gemfile:
gem "docit"
Then run:
bundle install
rails generate docit:install
The install generator does everything in one step:
- Creates
config/initializers/docit.rbwith default settings - Mounts the documentation engine at
/api-docsin your routes - Asks how you'd like to set up your docs:
- AI automatic docs — configure an AI provider, then Docit scans your routes and generates complete documentation for every endpoint
- Manual docs — Docit scans your routes and creates scaffolded doc files with TODO placeholders, injects
use_docsinto controllers, and lets you fill in the details - Skip — just install the base config and set up docs later
Visit /api-docs to see your interactive API documentation (Scalar by default, Swagger UI also available at /api-docs/swagger).
If you choose AI setup, Docit stores your provider config in .docit_ai.yml with restricted file permissions and adds that file to .gitignore when possible.
Configuration
Edit config/initializers/docit.rb:
Docit.configure do |config|
config.title = "My API"
config.version = "1.0.0"
config.description = "Backend API documentation"
# Documentation UI: :scalar (default) or :swagger
config.default_ui = :scalar
# Authentication: pick one (or multiple):
config.auth :bearer # Bearer token (JWT by default)
config.auth :basic # HTTP Basic
config.auth :api_key, name: "X-API-Key", # API key in header
location: "header"
# Tag descriptions (shown in the documentation sidebar):
config.tag "Users", description: "User account management"
config.tag "Auth", description: "Authentication endpoints"
# Server URLs (shown in the server dropdown):
config.server "https://api.example.com", description: "Production"
config.server "https://staging.example.com", description: "Staging"
config.server "http://localhost:3000", description: "Development"
end
Usage
Docit supports two styles for documenting endpoints. Choose whichever fits your project or mix both.
Style 1: Inline (simple APIs)
Add swagger_doc blocks directly in your controller:
class Api::V1::UsersController < ApplicationController
swagger_doc :index do
summary "List all users"
"Users"
response 200, "Users retrieved"
end
def index
# your code
end
end
Style 2: Separate doc files (recommended for larger APIs)
Keep controllers clean by defining docs in dedicated files:
# 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"
"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"
"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
end
# app/controllers/api/v1/users_controller.rb — stays clean!
class Api::V1::UsersController < ApplicationController
use_docs Api::V1::UsersDocs
def index
# pure business logic
end
def create
# pure business logic
end
end
You can also mix both styles — use use_docs for most actions and add inline swagger_doc for one-offs:
class Api::V1::UsersController < ApplicationController
use_docs Api::V1::UsersDocs # loads :index and :create from doc file
swagger_doc :destroy do # inline doc for this one action
summary "Delete user"
"Users"
response 204, "Deleted"
end
def index; end
def create; end
def destroy; end
end
Endpoint documentation DSL
The following examples work in both swagger_doc blocks and doc blocks.
Request bodies
swagger_doc :create do
summary "Create a user"
"Users"
request_body required: true do
property :email, type: :string, required: true, example: "user@example.com"
property :password, type: :string, required: true, format: :password
property :name, type: :string, example: "Jane Doe"
property :profile, type: :object do
property :bio, type: :string
property :avatar_url, type: :string, format: :uri
end
end
response 201, "User created" do
property :id, type: :integer, example: 1
property :email, type: :string, example: "user@example.com"
end
response 422, "Validation failed" do
property :errors, type: :object do
property :email, type: :array, items: :string
end
end
end
def create
# your code
end
Path parameters
swagger_doc :show do
summary "Get a user"
"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
def show
# your code
end
Enums
swagger_doc :index do
summary "List orders"
"Orders"
parameter :status, location: :query, type: :string,
enum: %w[pending shipped delivered],
description: "Filter by status"
response 200, "Orders list" do
property :orders, type: :array do
property :id, type: :integer
property :status, type: :string, enum: %w[pending shipped delivered]
end
end
end
Security
Mark endpoints as requiring authentication:
swagger_doc :destroy do
summary "Delete a user"
"Users"
security :bearer_auth # references the scheme from your config
response 204, "User deleted"
response 401, "Unauthorized"
end
Deprecated endpoints
swagger_doc :legacy_search do
summary "Search (legacy)"
"Search"
deprecated
response 200, "Results"
end
Nested objects and arrays
response 200, "Success" do
property :user, type: :object do
property :id, type: :integer
property :name, type: :string
property :addresses, type: :array do
property :street, type: :string
property :city, type: :string
property :zip, type: :string
end
end
end
Response examples
response 200, "User found" do
property :id, type: :integer
property :email, type: :string
example "admin_user",
{ id: 1, email: "admin@example.com" },
description: "An admin user"
example "regular_user",
{ id: 2, email: "user@example.com" },
description: "A regular user"
end
Shared schemas ($ref)
Define reusable schemas once and reference them across multiple endpoints:
# In config/initializers/docit.rb or a dedicated file:
Docit.define_schema :User do
property :id, type: :integer, example: 1
property :email, type: :string, example: "user@example.com"
property :name, type: :string, example: "Jane Doe"
property :address, type: :object do
property :street, type: :string
property :city, type: :string
end
end
Docit.define_schema :Error do
property :error, type: :string, example: "Not found"
property :details, type: :array, items: :string
end
Reference them in any endpoint with schema ref::
swagger_doc :show do
summary "Get user"
"Users"
response 200, "User found" do
schema ref: :User
end
response 404, "Not found" do
schema ref: :Error
end
end
swagger_doc :create do
summary "Create user"
"Users"
request_body required: true do
schema ref: :User
end
response 201, "Created" do
schema ref: :User
end
end
This outputs $ref: '#/components/schemas/User' in the spec — Swagger UI resolves it automatically.
File uploads
Use type: :file with content_type: "multipart/form-data" for file upload endpoints:
swagger_doc :upload_avatar do
summary "Upload avatar"
"Users"
request_body required: true, content_type: "multipart/form-data" do
property :avatar, type: :file, required: true, description: "Avatar image"
property :caption, type: :string
end
response 201, "Avatar uploaded" do
property :url, type: :string, format: :uri
end
end
type: :file maps to { type: "string", format: "binary" } in the OpenAPI spec.
AI Automatic Documentation
Docit can generate complete API documentation using AI. This works with OpenAI, Anthropic, or Groq (free tier available).
Quick start (included in install)
When you run rails generate docit:install and choose option 1 (AI automatic docs), everything is set up automatically — provider configuration, doc generation, controller wiring, and tag injection.
Before the first AI request, Docit warns that your controller source code will be sent to the selected provider and asks for confirmation in interactive terminals.
Standalone commands
You can also set up AI docs separately:
# Configure your AI provider (one-time setup)
rails generate docit:ai_setup
# Generate docs for all undocumented endpoints
rails docit:autodoc
# Generate docs for a specific controller
rails docit:autodoc[Api::V1::UsersController]
# Preview what would be generated without writing files
DRY_RUN=1 rails docit:autodoc
Supported providers
| Provider | Notes |
|---|---|
| OpenAI | Requires API key from platform.openai.com |
| Anthropic | Requires API key from console.anthropic.com |
| Groq | Free tier at console.groq.com |
All providers automatically retry on rate-limit (429) errors with exponential backoff, so free-tier usage works out of the box.
AI configuration is stored in .docit_ai.yml.
If your app does not have a .gitignore, add .docit_ai.yml manually.
What the AI generates
For each undocumented endpoint, Docit:
- Reads the controller source code
- Inspects the route (HTTP method, path, parameters)
- Writes the generated doc block to
app/docs/ - Injects
use_docsinto the controller - Adds tag descriptions to the initializer
Do not use AI autodoc on controllers that contain secrets, proprietary business rules, or internal comments you do not want sent to an external provider.
Documentation UIs
Docit ships with two documentation UIs, both reading from the same OpenAPI spec:
| Path | UI | Notes |
|---|---|---|
/api-docs |
Default (Scalar) | Configurable via config.default_ui |
/api-docs/scalar |
Scalar API Reference | Modern UI with built-in API client, dark mode, code samples |
/api-docs/swagger |
Swagger UI | Classic OpenAPI explorer |
/api-docs/spec |
Raw JSON | OpenAPI 3.0.3 spec |
Both UIs include a navigation bar to switch between them. Set config.default_ui = :swagger to make Swagger the default at /api-docs.
How it works
swagger_docregisters an Operation for each controller action in a global Registry- When someone visits
/api-docs/spec, Docit's SchemaGenerator combines all registered operations with your Rails routes (via RouteInspector) to produce an OpenAPI 3.0.3 JSON document - The Engine serves the configured documentation UI at
/api-docs, pointing it at the generated spec
The DSL is included in all controllers automatically via a Rails Engine initializer — no manual include needed if you're using ActionController::API or ActionController::Base.
Mounting at a different path
In config/routes.rb:
mount Docit::Engine => "/docs" # now at /docs instead of /api-docs
JSON spec only
If you just want the raw OpenAPI JSON (e.g., for code generation):
GET /api-docs/spec
Development
git clone https://github.com/S13G/docit.git
cd docit
bundle install
bundle exec rspec # run all tests
Contributing
Bug reports and pull requests are welcome on GitHub.