rails-autodoc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +63 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +81 -0
- data/.yardopts +3 -0
- data/Appraisals +26 -0
- data/CHANGELOG.md +20 -0
- data/CONTRIBUTING.md +54 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +298 -0
- data/LICENSE.txt +21 -0
- data/README.md +111 -0
- data/Rakefile +26 -0
- data/app/controllers/rails_autodoc/spec_controller.rb +52 -0
- data/config/routes.rb +6 -0
- data/docs/annotation-dsl.md +56 -0
- data/docs/architecture.md +37 -0
- data/docs/ci-integration.md +32 -0
- data/docs/configuration.md +48 -0
- data/docs/faq.md +29 -0
- data/docs/getting-started.md +54 -0
- data/docs/index.md +21 -0
- data/docs/inference-rules.md +74 -0
- data/docs/limitations.md +34 -0
- data/docs/migration-from-rswag.md +42 -0
- data/docs/serializer-support.md +25 -0
- data/lib/generators/rails_autodoc/install_generator.rb +34 -0
- data/lib/generators/rails_autodoc/templates/autodoc-verify.yml +19 -0
- data/lib/generators/rails_autodoc/templates/initializer.rb +20 -0
- data/lib/rails_autodoc/ast_traversal.rb +74 -0
- data/lib/rails_autodoc/configuration.rb +45 -0
- data/lib/rails_autodoc/dsl/controller_extensions.rb +65 -0
- data/lib/rails_autodoc/engine.rb +13 -0
- data/lib/rails_autodoc/generator.rb +54 -0
- data/lib/rails_autodoc/openapi_spec_builder.rb +334 -0
- data/lib/rails_autodoc/railtie.rb +25 -0
- data/lib/rails_autodoc/registry.rb +71 -0
- data/lib/rails_autodoc/response_inferencer.rb +158 -0
- data/lib/rails_autodoc/route_inspector.rb +139 -0
- data/lib/rails_autodoc/schema_mapper.rb +142 -0
- data/lib/rails_autodoc/serializers/active_model_serializer.rb +27 -0
- data/lib/rails_autodoc/serializers/alba.rb +39 -0
- data/lib/rails_autodoc/serializers/base.rb +19 -0
- data/lib/rails_autodoc/serializers/blueprinter.rb +27 -0
- data/lib/rails_autodoc/serializers/registry.rb +29 -0
- data/lib/rails_autodoc/strong_params_parser.rb +188 -0
- data/lib/rails_autodoc/tasks/autodoc.rake +26 -0
- data/lib/rails_autodoc/version.rb +5 -0
- data/lib/rails_autodoc.rb +47 -0
- data/mkdocs.yml +16 -0
- data/rails-autodoc.gemspec +61 -0
- data/spec/combustion/config.ru +4 -0
- data/spec/dummy/app/assets/config/manifest.js +1 -0
- data/spec/dummy/app/controllers/api/v1/users_controller.rb +45 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/config/application.rb +14 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +3 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/test.rb +12 -0
- data/spec/dummy/config/initializers/rails_autodoc.rb +8 -0
- data/spec/dummy/config/initializers/sqlite3_boolean.rb +8 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/db/migrate/001_create_users.rb +14 -0
- data/spec/dummy/db/schema.rb +12 -0
- data/spec/rails_autodoc/configuration_spec.rb +34 -0
- data/spec/rails_autodoc/dsl_integration_spec.rb +77 -0
- data/spec/rails_autodoc/engine_spec.rb +26 -0
- data/spec/rails_autodoc/gem_spec.rb +27 -0
- data/spec/rails_autodoc/generator_spec.rb +39 -0
- data/spec/rails_autodoc/golden_spec.rb +67 -0
- data/spec/rails_autodoc/integration_spec.rb +114 -0
- data/spec/rails_autodoc/registry_spec.rb +26 -0
- data/spec/rails_autodoc/response_inferencer_spec.rb +26 -0
- data/spec/rails_autodoc/route_inspector_spec.rb +56 -0
- data/spec/rails_autodoc/schema_mapper_spec.rb +42 -0
- data/spec/rails_autodoc/serializers/registry_spec.rb +33 -0
- data/spec/rails_autodoc/strong_params_parser_spec.rb +41 -0
- data/spec/spec_helper.rb +43 -0
- metadata +320 -0
data/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# rails-autodoc
|
|
2
|
+
|
|
3
|
+
Auto-generate OpenAPI 3.0 documentation from Rails routes, strong params, database schemas, and serializers.
|
|
4
|
+
|
|
5
|
+
**Problem:** Tools like rswag require maintaining RSpec specs that drift in legacy projects.
|
|
6
|
+
|
|
7
|
+
**Solution:** `rails-autodoc` reads the code you already maintain to ship features: `routes.rb`, `permit(...)`, and `db/schema.rb`.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
Add to your Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem "rails-autodoc", group: :development
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Install:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bundle install
|
|
21
|
+
rails generate rails_autodoc:install
|
|
22
|
+
rake autodoc:generate
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Open interactive docs:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
http://localhost:3000/api-docs
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## What gets generated automatically
|
|
32
|
+
|
|
33
|
+
| Feature | Support |
|
|
34
|
+
|---------|---------|
|
|
35
|
+
| Paths and HTTP verbs | Yes |
|
|
36
|
+
| Path parameters | Yes |
|
|
37
|
+
| Request body fields from strong params | Yes |
|
|
38
|
+
| Request field types from DB schema | Best effort |
|
|
39
|
+
| Query params from `params[:foo]` usage | Best effort |
|
|
40
|
+
| Response schemas | Serializer-aware, best effort |
|
|
41
|
+
| Validation rules / enums | Via annotation DSL |
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
# config/initializers/rails_autodoc.rb
|
|
47
|
+
RailsAutodoc.configure do |config|
|
|
48
|
+
config.title = "My API"
|
|
49
|
+
config.version = "1.0.0"
|
|
50
|
+
config.mount_path = "/api-docs"
|
|
51
|
+
config.output_path = Rails.root.join("openapi/openapi.yaml")
|
|
52
|
+
config.exclude_paths = [%r{^/rails/}, %r{^/api-docs}]
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Annotation DSL (optional)
|
|
57
|
+
|
|
58
|
+
Use when inference is not enough:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
class Api::V1::UsersController < ApplicationController
|
|
62
|
+
swagger_doc action: :create do
|
|
63
|
+
summary "Create a user"
|
|
64
|
+
body_param :role, :string, enum: %w[admin user]
|
|
65
|
+
response 201, ref: "User"
|
|
66
|
+
response 422, ref: "ValidationError"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Rake tasks
|
|
72
|
+
|
|
73
|
+
| Task | Description |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| `rake autodoc:generate` | Write OpenAPI YAML to configured output path |
|
|
76
|
+
| `rake autodoc:verify` | Fail if generated spec differs from committed file |
|
|
77
|
+
| `rake autodoc:routes` | Print inferred operations |
|
|
78
|
+
|
|
79
|
+
## CI integration
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
- run: bundle exec rake autodoc:verify
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Comparison
|
|
86
|
+
|
|
87
|
+
| Tool | Approach | Maintenance |
|
|
88
|
+
|------|----------|-------------|
|
|
89
|
+
| FastAPI | Types are the spec | Zero drift |
|
|
90
|
+
| rswag | RSpec DSL drives docs | High |
|
|
91
|
+
| swagger-blocks | Manual annotations | High |
|
|
92
|
+
| rails-autodoc | Convention inference | Low |
|
|
93
|
+
|
|
94
|
+
## Rails compatibility
|
|
95
|
+
|
|
96
|
+
Officially tested with Rails 5.2, 6.1, 7.0, 7.1, and 8.0 via Appraisal.
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
Full docs live in [`docs/`](docs/index.md):
|
|
101
|
+
|
|
102
|
+
- [Getting Started](docs/getting-started.md)
|
|
103
|
+
- [Configuration](docs/configuration.md)
|
|
104
|
+
- [Inference Rules](docs/inference-rules.md)
|
|
105
|
+
- [Annotation DSL](docs/annotation-dsl.md)
|
|
106
|
+
- [Limitations](docs/limitations.md)
|
|
107
|
+
- [Migration from rswag](docs/migration-from-rswag.md)
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT — see [LICENSE.txt](LICENSE.txt).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
|
|
8
|
+
task default: :spec
|
|
9
|
+
|
|
10
|
+
task :environment do
|
|
11
|
+
require "rails"
|
|
12
|
+
require "rails_autodoc"
|
|
13
|
+
require "combustion"
|
|
14
|
+
|
|
15
|
+
Combustion.path = "spec/dummy"
|
|
16
|
+
Combustion.initialize! :all unless Combustion::Application.initialized?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
load File.expand_path("lib/rails_autodoc/tasks/autodoc.rake", __dir__)
|
|
20
|
+
|
|
21
|
+
namespace :appraisal do
|
|
22
|
+
desc "Run specs against all Rails versions"
|
|
23
|
+
task :spec do
|
|
24
|
+
sh "bundle exec appraisal rake spec"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAutodoc
|
|
4
|
+
class SpecController < ActionController::Base
|
|
5
|
+
def show
|
|
6
|
+
spec = cached_spec
|
|
7
|
+
render json: spec
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def ui
|
|
11
|
+
render html: swagger_ui_html.html_safe
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def cached_spec
|
|
17
|
+
return self.class.cached_spec if RailsAutodoc.config.cache_spec_in_dev && self.class.cached_spec
|
|
18
|
+
|
|
19
|
+
self.class.cached_spec = Generator.new.generate
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def swagger_ui_html
|
|
23
|
+
spec_url = "#{RailsAutodoc.config.mount_path}/spec.json"
|
|
24
|
+
<<~HTML
|
|
25
|
+
<!DOCTYPE html>
|
|
26
|
+
<html lang="en">
|
|
27
|
+
<head>
|
|
28
|
+
<meta charset="UTF-8" />
|
|
29
|
+
<title>#{RailsAutodoc.config.title} API Docs</title>
|
|
30
|
+
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" />
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<div id="swagger-ui"></div>
|
|
34
|
+
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
|
|
35
|
+
<script>
|
|
36
|
+
window.onload = function() {
|
|
37
|
+
SwaggerUIBundle({
|
|
38
|
+
url: "#{spec_url}",
|
|
39
|
+
dom_id: "#swagger-ui"
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
</script>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
45
|
+
HTML
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class << self
|
|
49
|
+
attr_accessor :cached_spec
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Annotation DSL
|
|
2
|
+
|
|
3
|
+
Use annotations when inference is incomplete.
|
|
4
|
+
|
|
5
|
+
## Basic usage
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
class Api::V1::UsersController < ApplicationController
|
|
9
|
+
swagger_doc action: :create do
|
|
10
|
+
summary "Create a user"
|
|
11
|
+
description "Creates a user with the provided attributes"
|
|
12
|
+
tag "Users"
|
|
13
|
+
deprecated false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Request overrides
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
swagger_doc action: :create do
|
|
22
|
+
body_param :role, :string, enum: %w[admin user]
|
|
23
|
+
query_param :include, :string, required: false
|
|
24
|
+
|
|
25
|
+
request_body type: :object, properties: {
|
|
26
|
+
user: { type: :object }
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Response overrides
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
swagger_doc action: :create do
|
|
35
|
+
response 201, ref: "User"
|
|
36
|
+
response 422, ref: "ValidationError"
|
|
37
|
+
end
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Security
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
swagger_doc action: :index do
|
|
44
|
+
security :bearer_auth
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Exclude endpoints
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
swagger_doc action: :debug do
|
|
52
|
+
exclude true
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Annotations always override inferred values for the same operation.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Pipeline
|
|
4
|
+
|
|
5
|
+
1. `RouteInspector` discovers operations from Rails routes
|
|
6
|
+
2. `StrongParamsParser` extracts request schemas from controller AST
|
|
7
|
+
3. `SchemaMapper` maps ActiveRecord columns to OpenAPI types
|
|
8
|
+
4. `ResponseInferencer` inspects render/head calls
|
|
9
|
+
5. Serializer adapters enrich response schemas
|
|
10
|
+
6. `Registry` merges `swagger_doc` overrides
|
|
11
|
+
7. `OpenapiSpecBuilder` assembles OpenAPI 3.0.3 output
|
|
12
|
+
8. `Generator` writes YAML or serves JSON via the engine
|
|
13
|
+
|
|
14
|
+
## Key classes
|
|
15
|
+
|
|
16
|
+
| Class | Responsibility |
|
|
17
|
+
|-------|------------------|
|
|
18
|
+
| `RailsAutodoc::RouteInspector` | Route discovery |
|
|
19
|
+
| `RailsAutodoc::StrongParamsParser` | AST permit extraction |
|
|
20
|
+
| `RailsAutodoc::SchemaMapper` | DB schema mapping |
|
|
21
|
+
| `RailsAutodoc::ResponseInferencer` | Response inference |
|
|
22
|
+
| `RailsAutodoc::OpenapiSpecBuilder` | OpenAPI assembly |
|
|
23
|
+
| `RailsAutodoc::Generator` | Orchestration and export |
|
|
24
|
+
| `RailsAutodoc::Engine` | Swagger UI and live spec |
|
|
25
|
+
|
|
26
|
+
## Extension points
|
|
27
|
+
|
|
28
|
+
- Serializer adapters under `lib/rails_autodoc/serializers/`
|
|
29
|
+
- Annotation DSL via `swagger_doc`
|
|
30
|
+
- Configuration in `RailsAutodoc.configure`
|
|
31
|
+
|
|
32
|
+
## Testing strategy
|
|
33
|
+
|
|
34
|
+
- Combustion dummy Rails app in `spec/dummy/`
|
|
35
|
+
- Unit specs per component
|
|
36
|
+
- Appraisal matrix for Rails 5.2 through 8.0
|
|
37
|
+
- Golden OpenAPI fixtures for regression testing
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# CI Integration
|
|
2
|
+
|
|
3
|
+
Prevent documentation drift by verifying the committed OpenAPI file matches generated output.
|
|
4
|
+
|
|
5
|
+
## Local verify
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
rake autodoc:generate
|
|
9
|
+
rake autodoc:verify
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## GitHub Actions
|
|
13
|
+
|
|
14
|
+
The install generator adds `.github/workflows/autodoc-verify.yml`:
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
- run: bundle exec rake autodoc:verify
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Recommended workflow
|
|
21
|
+
|
|
22
|
+
1. Commit `openapi/openapi.yaml`
|
|
23
|
+
2. Run `autodoc:verify` in CI on every pull request
|
|
24
|
+
3. Regenerate locally when routes or strong params change
|
|
25
|
+
|
|
26
|
+
## Debugging inferred routes
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
rake autodoc:routes
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Prints verb, path, controller, and action for every discovered operation.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Configure the gem in `config/initializers/rails_autodoc.rb`:
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
RailsAutodoc.configure do |config|
|
|
7
|
+
config.title = "My App API"
|
|
8
|
+
config.version = "1.0.0"
|
|
9
|
+
config.description = "Auto-generated API documentation"
|
|
10
|
+
config.mount_path = "/api-docs"
|
|
11
|
+
config.output_path = Rails.root.join("openapi/openapi.yaml")
|
|
12
|
+
config.exclude_paths = [%r{^/rails/}, %r{^/api-docs}]
|
|
13
|
+
config.cache_spec_in_dev = true
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Options
|
|
18
|
+
|
|
19
|
+
| Option | Default | Description |
|
|
20
|
+
|--------|---------|-------------|
|
|
21
|
+
| `title` | `"Rails API"` | OpenAPI info title |
|
|
22
|
+
| `version` | `"1.0.0"` | OpenAPI info version |
|
|
23
|
+
| `description` | auto | OpenAPI info description |
|
|
24
|
+
| `mount_path` | `"/api-docs"` | Engine mount path |
|
|
25
|
+
| `output_path` | `openapi/openapi.yaml` | Static export path |
|
|
26
|
+
| `exclude_paths` | internal routes | Regex list of paths to skip |
|
|
27
|
+
| `include_engines` | `[]` | Additional engines to scan |
|
|
28
|
+
| `default_security` | `nil` | Default security scheme key |
|
|
29
|
+
| `security_schemes` | `{}` | OpenAPI security scheme definitions |
|
|
30
|
+
| `cache_spec_in_dev` | `true` | Cache live spec in development |
|
|
31
|
+
| `servers` | localhost | OpenAPI servers array |
|
|
32
|
+
|
|
33
|
+
## Security example
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
config.security_schemes = {
|
|
37
|
+
"bearer_auth" => {
|
|
38
|
+
"type" => "http",
|
|
39
|
+
"scheme" => "bearer",
|
|
40
|
+
"bearerFormat" => "JWT"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
config.default_security = :bearer_auth
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Production guidance
|
|
47
|
+
|
|
48
|
+
Serve static `openapi/openapi.yaml` in production rather than mounting the engine publicly unless docs should be externally accessible.
|
data/docs/faq.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# FAQ
|
|
2
|
+
|
|
3
|
+
## Why not use FastAPI-style type-driven docs?
|
|
4
|
+
|
|
5
|
+
Rails APIs rarely declare request/response contracts in types. `rails-autodoc` meets teams where they are: strong params and routes.
|
|
6
|
+
|
|
7
|
+
## Will docs drift?
|
|
8
|
+
|
|
9
|
+
Static exports can drift if you forget to regenerate. Use `rake autodoc:verify` in CI to catch drift.
|
|
10
|
+
|
|
11
|
+
## How accurate are generated schemas?
|
|
12
|
+
|
|
13
|
+
Good for endpoint discovery, request field names, and common REST patterns. Validation rules, enums, and complex response shapes need DSL overrides or serializer gems.
|
|
14
|
+
|
|
15
|
+
## Does it work on legacy Rails 5 apps?
|
|
16
|
+
|
|
17
|
+
Yes. The gem targets Rails 5.2 through 8.x and uses CDN-based Swagger UI to avoid asset pipeline dependencies.
|
|
18
|
+
|
|
19
|
+
## Can I hide internal routes?
|
|
20
|
+
|
|
21
|
+
Yes. Use `config.exclude_paths` regexes or `swagger_doc { exclude true }`.
|
|
22
|
+
|
|
23
|
+
## Does it replace rswag contract tests?
|
|
24
|
+
|
|
25
|
+
No. It replaces documentation maintenance burden. Keep contract tests if you rely on them for response validation.
|
|
26
|
+
|
|
27
|
+
## What OpenAPI version is generated?
|
|
28
|
+
|
|
29
|
+
OpenAPI 3.0.3.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
Add the gem to your Gemfile:
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
gem "rails-autodoc", group: :development
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Run Bundler:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bundle install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Install generator
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
rails generate rails_autodoc:install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This creates:
|
|
24
|
+
|
|
25
|
+
- `config/initializers/rails_autodoc.rb`
|
|
26
|
+
- `openapi/` output directory
|
|
27
|
+
- Engine mount at `/api-docs`
|
|
28
|
+
- `.github/workflows/autodoc-verify.yml`
|
|
29
|
+
|
|
30
|
+
## Generate documentation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
rake autodoc:generate
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Output defaults to `openapi/openapi.yaml`.
|
|
37
|
+
|
|
38
|
+
## View interactive docs
|
|
39
|
+
|
|
40
|
+
Start Rails and visit:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
http://localhost:3000/api-docs
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The engine serves Swagger UI and a live spec at `/api-docs/spec.json`.
|
|
47
|
+
|
|
48
|
+
## Verify in CI
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
rake autodoc:verify
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Commit the generated YAML and run this task in CI to prevent documentation drift.
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# rails-autodoc
|
|
2
|
+
|
|
3
|
+
Generate OpenAPI 3.0 documentation from Rails conventions — routes, strong params, database schemas, and serializers.
|
|
4
|
+
|
|
5
|
+
## Why this gem exists
|
|
6
|
+
|
|
7
|
+
Legacy Rails APIs often have outdated rswag specs. `rails-autodoc` generates docs from files teams already update to ship features:
|
|
8
|
+
|
|
9
|
+
- `config/routes.rb`
|
|
10
|
+
- `params.require(...).permit(...)`
|
|
11
|
+
- `db/schema.rb`
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Zero-config baseline documentation
|
|
16
|
+
- Optional `swagger_doc` DSL for edge cases
|
|
17
|
+
- Swagger UI at `/api-docs`
|
|
18
|
+
- CI drift detection via `rake autodoc:verify`
|
|
19
|
+
- Rails 5.2 through 8.x support
|
|
20
|
+
|
|
21
|
+
See [Getting Started](getting-started.md) to install the gem.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Inference Rules
|
|
2
|
+
|
|
3
|
+
`rails-autodoc` builds OpenAPI operations from Rails conventions.
|
|
4
|
+
|
|
5
|
+
## Routes
|
|
6
|
+
|
|
7
|
+
Source: `Rails.application.routes`
|
|
8
|
+
|
|
9
|
+
Extracted data:
|
|
10
|
+
|
|
11
|
+
- HTTP verb
|
|
12
|
+
- Path template (`/users/:id` -> `/users/{id}`)
|
|
13
|
+
- Controller and action
|
|
14
|
+
- Path parameters
|
|
15
|
+
- Tags from controller namespace
|
|
16
|
+
|
|
17
|
+
## Strong params
|
|
18
|
+
|
|
19
|
+
Source: controller AST via `parser`
|
|
20
|
+
|
|
21
|
+
Supported patterns:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
params.require(:user).permit(:name, :email)
|
|
25
|
+
params.require(:user).permit(:name, address: [:street, :city])
|
|
26
|
+
params.require(:user).permit(tags: [])
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Action mapping:
|
|
30
|
+
|
|
31
|
+
- Looks for `*_params` method calls inside the action
|
|
32
|
+
- Falls back to the first `*_params` method in the controller
|
|
33
|
+
|
|
34
|
+
## Database schema
|
|
35
|
+
|
|
36
|
+
Source: `db/schema.rb`
|
|
37
|
+
|
|
38
|
+
- Maps model attributes to OpenAPI types
|
|
39
|
+
- Applies types to request fields when names match model columns
|
|
40
|
+
- Generates `components.schemas` entries for ActiveRecord models
|
|
41
|
+
|
|
42
|
+
## Query params
|
|
43
|
+
|
|
44
|
+
Source: AST scan of action body
|
|
45
|
+
|
|
46
|
+
Detects:
|
|
47
|
+
|
|
48
|
+
- `params[:page]`
|
|
49
|
+
- `params.fetch(:filter)`
|
|
50
|
+
|
|
51
|
+
Defaults to optional string parameters.
|
|
52
|
+
|
|
53
|
+
## Responses
|
|
54
|
+
|
|
55
|
+
Source: AST scan of `render` and `head` calls
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
|
|
59
|
+
- `render json: @user` -> model-based schema reference
|
|
60
|
+
- `render json: user, status: :created` -> HTTP 201
|
|
61
|
+
- `head :no_content` -> HTTP 204
|
|
62
|
+
|
|
63
|
+
Default status by verb when no render call is found:
|
|
64
|
+
|
|
65
|
+
| Verb | Status |
|
|
66
|
+
|------|--------|
|
|
67
|
+
| GET | 200 |
|
|
68
|
+
| POST | 201 |
|
|
69
|
+
| PUT/PATCH | 200 |
|
|
70
|
+
| DELETE | 204 |
|
|
71
|
+
|
|
72
|
+
## Serializers
|
|
73
|
+
|
|
74
|
+
If Alba, Blueprinter, or ActiveModel::Serializer is present, response schemas use serializer field definitions.
|
data/docs/limitations.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Limitations
|
|
2
|
+
|
|
3
|
+
`rails-autodoc` is convention-driven. It is not a replacement for contract-first API design.
|
|
4
|
+
|
|
5
|
+
## Known gaps
|
|
6
|
+
|
|
7
|
+
| Scenario | Behavior |
|
|
8
|
+
|----------|----------|
|
|
9
|
+
| `params.permit!` | Not parsed; empty or generic schema |
|
|
10
|
+
| Dynamic param keys | Not inferred |
|
|
11
|
+
| Params in service objects | Not inferred |
|
|
12
|
+
| GraphQL endpoints | Out of scope |
|
|
13
|
+
| Grape APIs | Out of scope for v1 |
|
|
14
|
+
| Conditional strong params | Best effort only |
|
|
15
|
+
| Complex serializer logic | Field list only, no computed attribute types |
|
|
16
|
+
|
|
17
|
+
## Accuracy expectations
|
|
18
|
+
|
|
19
|
+
- Baseline without annotations: ~60-70% useful coverage
|
|
20
|
+
- With light DSL overrides: ~90%+ for most REST APIs
|
|
21
|
+
|
|
22
|
+
## When to use annotations
|
|
23
|
+
|
|
24
|
+
- Enum values
|
|
25
|
+
- Custom response codes
|
|
26
|
+
- Authentication requirements
|
|
27
|
+
- Non-standard request bodies
|
|
28
|
+
- Hiding internal/debug endpoints
|
|
29
|
+
|
|
30
|
+
## When not to use this gem
|
|
31
|
+
|
|
32
|
+
- Public APIs requiring strict contract guarantees
|
|
33
|
+
- APIs with minimal Rails conventions
|
|
34
|
+
- Greenfield projects where OpenAPI-first tooling is available
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Migration from rswag
|
|
2
|
+
|
|
3
|
+
## Philosophy difference
|
|
4
|
+
|
|
5
|
+
| rswag | rails-autodoc |
|
|
6
|
+
|-------|---------------|
|
|
7
|
+
| Tests drive docs | Conventions drive docs |
|
|
8
|
+
| High accuracy when maintained | Good accuracy with low maintenance |
|
|
9
|
+
| Requires RSpec DSL | Works without extra specs |
|
|
10
|
+
|
|
11
|
+
## Coexistence
|
|
12
|
+
|
|
13
|
+
You can run both during migration:
|
|
14
|
+
|
|
15
|
+
1. Install `rails-autodoc`
|
|
16
|
+
2. Generate baseline docs with `rake autodoc:generate`
|
|
17
|
+
3. Compare against existing rswag output
|
|
18
|
+
4. Remove rswag once satisfied
|
|
19
|
+
|
|
20
|
+
## Mapping concepts
|
|
21
|
+
|
|
22
|
+
| rswag | rails-autodoc |
|
|
23
|
+
|-------|---------------|
|
|
24
|
+
| `path` | inferred from routes |
|
|
25
|
+
| `parameter` | inferred from strong params / query usage |
|
|
26
|
+
| `response` | inferred from render calls or `swagger_doc` |
|
|
27
|
+
| `swagger_helper` config | `RailsAutodoc.configure` |
|
|
28
|
+
|
|
29
|
+
## Recommended migration path for legacy apps
|
|
30
|
+
|
|
31
|
+
1. Run `rails generate rails_autodoc:install`
|
|
32
|
+
2. Generate docs on day one without changing controllers
|
|
33
|
+
3. Add `swagger_doc` only where inference is wrong
|
|
34
|
+
4. Add `autodoc:verify` to CI
|
|
35
|
+
5. Deprecate outdated rswag specs
|
|
36
|
+
|
|
37
|
+
## What you can delete after migration
|
|
38
|
+
|
|
39
|
+
- rswag request specs used only for documentation
|
|
40
|
+
- Manual swagger YAML maintained separately from code
|
|
41
|
+
|
|
42
|
+
Keep rswag if you also use it for contract testing against the generated spec.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Serializer Support
|
|
2
|
+
|
|
3
|
+
`rails-autodoc` detects serializer gems at runtime and uses them for response schemas.
|
|
4
|
+
|
|
5
|
+
## Supported adapters
|
|
6
|
+
|
|
7
|
+
| Gem | Detection | Schema source |
|
|
8
|
+
|-----|-----------|---------------|
|
|
9
|
+
| Alba | `defined?(Alba)` | declared attributes |
|
|
10
|
+
| Blueprinter | `defined?(Blueprinter)` | `fields` hash |
|
|
11
|
+
| ActiveModel::Serializer | `defined?(ActiveModel::Serializer)` | `_attributes` |
|
|
12
|
+
|
|
13
|
+
Adapters are optional soft dependencies. If no serializer gem is present, responses fall back to model schemas or generic objects.
|
|
14
|
+
|
|
15
|
+
## Adding a custom adapter
|
|
16
|
+
|
|
17
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-a-serializer-adapter).
|
|
18
|
+
|
|
19
|
+
Each adapter implements:
|
|
20
|
+
|
|
21
|
+
- `#detect?`
|
|
22
|
+
- `#attributes_for(serializer_class)`
|
|
23
|
+
- `#schema_for(serializer_class)`
|
|
24
|
+
|
|
25
|
+
Register new adapters in `RailsAutodoc::Serializers::Registry`.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RailsAutodoc
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
|
9
|
+
|
|
10
|
+
desc "Install rails-autodoc configuration, output directory, and optional CI workflow"
|
|
11
|
+
|
|
12
|
+
def create_initializer
|
|
13
|
+
template "initializer.rb", "config/initializers/rails_autodoc.rb"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create_output_directory
|
|
17
|
+
empty_directory "openapi"
|
|
18
|
+
create_file "openapi/.keep"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def mount_engine
|
|
22
|
+
route <<~ROUTE
|
|
23
|
+
|
|
24
|
+
# Auto-generated API documentation (development/staging recommended)
|
|
25
|
+
mount RailsAutodoc::Engine => "/api-docs"
|
|
26
|
+
ROUTE
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_ci_workflow
|
|
30
|
+
template "autodoc-verify.yml", ".github/workflows/autodoc-verify.yml"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|