docit 0.4.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +25 -1
- data/README.md +475 -21
- data/TROUBLESHOOTING.md +57 -0
- data/app/controllers/docit/ui_controller.rb +23 -3
- data/config/routes.rb +2 -0
- data/docs/images/scalar_image.png +0 -0
- data/docs/images/swagger_image.png +0 -0
- data/lib/docit/ai/autodoc_runner.rb +9 -4
- data/lib/docit/ai/doc_writer.rb +3 -3
- data/lib/docit/ai/groq_client.rb +4 -8
- data/lib/docit/ai/scaffold_generator.rb +3 -1
- data/lib/docit/ai/tag_injector.rb +1 -1
- data/lib/docit/builders/response_builder.rb +12 -2
- data/lib/docit/configuration.rb +5 -4
- data/lib/docit/schema_generator.rb +49 -31
- data/lib/docit/system_graph/edge.rb +29 -0
- data/lib/docit/system_graph/generator.rb +15 -0
- data/lib/docit/system_graph/graph.rb +55 -0
- data/lib/docit/system_graph/node.rb +32 -0
- data/lib/docit/system_graph/rails_analyzer.rb +278 -0
- data/lib/docit/system_graph/source_scanner.rb +76 -0
- data/lib/docit/system_graph.rb +8 -0
- data/lib/docit/ui/base_renderer.rb +49 -21
- data/lib/docit/ui/system_renderer.rb +113 -0
- data/lib/docit/ui/system_script.rb +1416 -0
- data/lib/docit/ui/system_styles.rb +566 -0
- data/lib/docit/version.rb +1 -1
- data/lib/docit.rb +4 -0
- data/lib/generators/docit/install/templates/initializer.rb +4 -0
- metadata +17 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad97aecf5e4f97baffb4f944fa8f8a62b449846714e1c2dd2e8bbdc9a167ee22
|
|
4
|
+
data.tar.gz: f638754ff073096c6904db2e5d394413e2f1c579966b97af831cfe93ae91af51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9efd42b242a8c94f0a4372689205e736819ff0fb8e75fa29e95e708899adefacbefec43af0987449fbd3fd766dbb78b1c3f750d51d3141ee4bcb353d08cf9490
|
|
7
|
+
data.tar.gz: b871fd59eabc84e1f135a4638527f7042b48ee033f17f7bd17378ab7002308e81202c37269912ca5883af30f06c1a7a6a8dc4d121d10573225cb464226f91251
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,28 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [0.6.0] - 2026-06-20
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- Property options for richer schemas: `default`, `nullable`, `read_only`, and `write_only` on any `property` in a request body, response, or shared schema — emitted as OpenAPI `default`, `nullable`, `readOnly`, and `writeOnly`. Falsy values like `default: false` and `default: 0` are preserved
|
|
5
|
+
- Response headers: declare them inside a `response` block with `header "X-RateLimit-Remaining", type: :integer, description: "..."`, emitted as an OpenAPI `headers` object on that response
|
|
6
|
+
- System Map `uses_schema` edges: documented endpoints that reference a shared schema (`schema ref: :User`) are now linked to that schema node in the graph
|
|
7
|
+
- `TROUBLESHOOTING.md` covering common questions (missing routes, ignored options, AI setup, production exposure)
|
|
8
|
+
- README section on restricting access to the docs endpoints in production
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- README documents the new property options and response headers
|
|
12
|
+
|
|
13
|
+
### Removed
|
|
14
|
+
- The AI "Explain section" / system insights feature and its endpoint (`/api-docs/system/insights`). It was unauthenticated — exposing an outbound, billable AI call and rendering AI output without escaping — so it has been removed. The rest of the System Map (diagram, docs view, search, theming, PNG export) is unchanged, and `rails docit:autodoc` is unaffected
|
|
15
|
+
|
|
16
|
+
## [0.5.0] - 2026-05-31
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- **System Map**: a local, deterministic architecture graph at `/api-docs/system` (JSON at `/api-docs/system.json`), built from Rails routes, controllers, actions, Docit docs coverage, schemas, models, and source-derived service/job/mailer nodes — no external service required
|
|
20
|
+
- System Map navigation alongside the Scalar and Swagger UIs
|
|
21
|
+
- Light and dark themes for the System Map (light by default), with a toolbar toggle persisted across visits
|
|
22
|
+
- **Diagram view**: interactive architecture graph with drag-to-arrange, scroll-to-zoom, pan, fit-to-screen, and PNG export; click a node to inspect its connections, with neighbouring nodes highlighted; `/` focuses node search
|
|
23
|
+
- Endpoints-section filter for the diagram (Users, Orders, …) that narrows the graph to one resource and everything it touches
|
|
24
|
+
- **Docs view**: a request/response reference grouped by resource, with human-readable endpoint titles derived from doc summaries (falling back to REST conventions), a documentation-coverage indicator per section, and a detail panel showing parameters, request body, and responses
|
|
25
|
+
- AI section explanations in the Docs view: "Explain section" summarises how a resource's endpoints work together, gated by a coverage warning so undocumented sections don't silently spend tokens
|
|
2
26
|
|
|
3
27
|
## [0.4.0] - 2026-04-18
|
|
4
28
|
|
data/README.md
CHANGED
|
@@ -11,7 +11,51 @@ Decorator-style API documentation for Ruby on Rails. Write OpenAPI 3.0.3 docs wi
|
|
|
11
11
|
### Swagger
|
|
12
12
|

|
|
13
13
|
|
|
14
|
-
> **Full documentation:** [
|
|
14
|
+
> **Full documentation:** [doc-it.dev/docs](https://doc-it.dev/docs)
|
|
15
|
+
|
|
16
|
+
## Table Of Contents
|
|
17
|
+
|
|
18
|
+
- Getting started
|
|
19
|
+
- [Installation](#installation)
|
|
20
|
+
- [Configuration](#configuration)
|
|
21
|
+
- [Usage](#usage)
|
|
22
|
+
- Documentation styles
|
|
23
|
+
- [Style 1: Inline (simple APIs)](#style-1-inline-simple-apis)
|
|
24
|
+
- [Style 2: Separate doc files (recommended for larger APIs)](#style-2-separate-doc-files-recommended-for-larger-apis)
|
|
25
|
+
- Endpoint DSL reference
|
|
26
|
+
- [Endpoint documentation DSL](#endpoint-documentation-dsl)
|
|
27
|
+
- [Request bodies](#request-bodies)
|
|
28
|
+
- [Path parameters](#path-parameters)
|
|
29
|
+
- [Enums](#enums)
|
|
30
|
+
- [Property options](#property-options)
|
|
31
|
+
- [Response headers](#response-headers)
|
|
32
|
+
- [Security](#security)
|
|
33
|
+
- [Deprecated endpoints](#deprecated-endpoints)
|
|
34
|
+
- [Nested objects and arrays](#nested-objects-and-arrays)
|
|
35
|
+
- [Response examples](#response-examples)
|
|
36
|
+
- [Shared schemas (`$ref`)](#shared-schemas-ref)
|
|
37
|
+
- [File uploads](#file-uploads)
|
|
38
|
+
- AI documentation
|
|
39
|
+
- [AI Automatic Documentation](#ai-automatic-documentation)
|
|
40
|
+
- [Quick start (included in install)](#quick-start-included-in-install)
|
|
41
|
+
- [Standalone commands](#standalone-commands)
|
|
42
|
+
- [Supported providers](#supported-providers)
|
|
43
|
+
- [What the AI generates](#what-the-ai-generates)
|
|
44
|
+
- Runtime and development
|
|
45
|
+
- [Documentation UIs](#documentation-uis)
|
|
46
|
+
- [System Map](#system-map)
|
|
47
|
+
- [How it works](#how-it-works)
|
|
48
|
+
- [Mounting at a different path](#mounting-at-a-different-path)
|
|
49
|
+
- [Restricting access in production](#restricting-access-in-production)
|
|
50
|
+
- [JSON spec only](#json-spec-only)
|
|
51
|
+
- [Development](#development)
|
|
52
|
+
- [Contributing](#contributing)
|
|
53
|
+
- [License](#license)
|
|
54
|
+
- Project docs
|
|
55
|
+
- [CHANGELOG](CHANGELOG.md)
|
|
56
|
+
- [TROUBLESHOOTING](TROUBLESHOOTING.md)
|
|
57
|
+
- [CONTRIBUTING](CONTRIBUTING.md)
|
|
58
|
+
- [CODE OF CONDUCT](CODE_OF_CONDUCT.md)
|
|
15
59
|
|
|
16
60
|
## Installation
|
|
17
61
|
|
|
@@ -39,6 +83,8 @@ The install generator does everything in one step:
|
|
|
39
83
|
|
|
40
84
|
Visit `/api-docs` to see your interactive API documentation (Scalar by default, Swagger UI also available at `/api-docs/swagger`).
|
|
41
85
|
|
|
86
|
+
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.
|
|
87
|
+
|
|
42
88
|
## Configuration
|
|
43
89
|
|
|
44
90
|
Edit `config/initializers/docit.rb`:
|
|
@@ -48,19 +94,39 @@ Docit.configure do |config|
|
|
|
48
94
|
config.title = "My API"
|
|
49
95
|
config.version = "1.0.0"
|
|
50
96
|
config.description = "Backend API documentation"
|
|
51
|
-
config.default_ui = :scalar # :scalar (default) or :swagger
|
|
52
97
|
|
|
53
|
-
|
|
98
|
+
# Documentation UI: :scalar (default) or :swagger
|
|
99
|
+
config.default_ui = :scalar
|
|
100
|
+
|
|
101
|
+
# Authentication: pick one (or multiple):
|
|
102
|
+
config.auth :bearer # Bearer token (JWT by default)
|
|
103
|
+
config.auth :basic # HTTP Basic
|
|
104
|
+
config.auth :api_key, name: "X-API-Key", # API key in header
|
|
105
|
+
location: "header"
|
|
106
|
+
|
|
107
|
+
# Tag descriptions (shown in the documentation sidebar):
|
|
54
108
|
config.tag "Users", description: "User account management"
|
|
109
|
+
config.tag "Auth", description: "Authentication endpoints"
|
|
110
|
+
|
|
111
|
+
# Server URLs (shown in the server dropdown):
|
|
55
112
|
config.server "https://api.example.com", description: "Production"
|
|
113
|
+
config.server "https://staging.example.com", description: "Staging"
|
|
114
|
+
config.server "http://localhost:3000", description: "Development"
|
|
115
|
+
|
|
116
|
+
# License information:
|
|
117
|
+
config.license name: "MIT", url: "https://opensource.org/licenses/MIT"
|
|
118
|
+
|
|
119
|
+
# Contact information:
|
|
120
|
+
config.contact name: "API Team", email: "api@example.com", url: "https://example.com/support"
|
|
121
|
+
|
|
122
|
+
# Terms of service:
|
|
123
|
+
config.terms_of_service "https://example.com/tos"
|
|
56
124
|
end
|
|
57
125
|
```
|
|
58
126
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
## Quick Start
|
|
127
|
+
## Usage
|
|
62
128
|
|
|
63
|
-
Docit supports two styles. Choose whichever fits your project or mix both.
|
|
129
|
+
Docit supports two styles for documenting endpoints. Choose whichever fits your project or mix both.
|
|
64
130
|
|
|
65
131
|
### Style 1: Inline (simple APIs)
|
|
66
132
|
|
|
@@ -73,7 +139,6 @@ class Api::V1::UsersController < ApplicationController
|
|
|
73
139
|
tags "Users"
|
|
74
140
|
response 200, "Users retrieved"
|
|
75
141
|
end
|
|
76
|
-
|
|
77
142
|
def index
|
|
78
143
|
# your code
|
|
79
144
|
end
|
|
@@ -93,62 +158,451 @@ module Api::V1::UsersDocs
|
|
|
93
158
|
|
|
94
159
|
doc :index do
|
|
95
160
|
summary "List all users"
|
|
161
|
+
description "Returns a paginated list of users"
|
|
96
162
|
tags "Users"
|
|
97
163
|
|
|
164
|
+
parameter :page, location: :query, type: :integer, description: "Page number"
|
|
165
|
+
|
|
98
166
|
response 200, "Users retrieved" do
|
|
99
167
|
property :users, type: :array, items: :object do
|
|
100
168
|
property :id, type: :integer, example: 1
|
|
101
169
|
property :email, type: :string, example: "user@example.com"
|
|
102
170
|
end
|
|
171
|
+
property :total, type: :integer, example: 42
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
doc :create do
|
|
176
|
+
summary "Create a user"
|
|
177
|
+
tags "Users"
|
|
178
|
+
|
|
179
|
+
request_body required: true do
|
|
180
|
+
property :email, type: :string, required: true
|
|
181
|
+
property :password, type: :string, required: true, format: :password
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
response 201, "User created" do
|
|
185
|
+
property :id, type: :integer
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
response 422, "Validation failed" do
|
|
189
|
+
property :errors, type: :object do
|
|
190
|
+
property :email, type: :array, items: :string
|
|
191
|
+
end
|
|
103
192
|
end
|
|
104
193
|
end
|
|
105
194
|
end
|
|
106
|
-
```
|
|
107
195
|
|
|
108
|
-
|
|
109
|
-
# app/controllers/api/v1/users_controller.rb
|
|
196
|
+
# app/controllers/api/v1/users_controller.rb — stays clean!
|
|
110
197
|
class Api::V1::UsersController < ApplicationController
|
|
111
198
|
use_docs Api::V1::UsersDocs
|
|
112
199
|
|
|
113
200
|
def index
|
|
114
201
|
# pure business logic
|
|
115
202
|
end
|
|
203
|
+
|
|
204
|
+
def create
|
|
205
|
+
# pure business logic
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
You can also mix both styles — use `use_docs` for most actions and add inline `doc_for` for one-offs:
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
class Api::V1::UsersController < ApplicationController
|
|
214
|
+
use_docs Api::V1::UsersDocs # loads :index and :create from doc file
|
|
215
|
+
|
|
216
|
+
doc_for :destroy do # inline doc for this one action
|
|
217
|
+
summary "Delete user"
|
|
218
|
+
tags "Users"
|
|
219
|
+
response 204, "Deleted"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def index; end
|
|
223
|
+
def create; end
|
|
224
|
+
def destroy; end
|
|
225
|
+
end
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Endpoint documentation DSL
|
|
229
|
+
|
|
230
|
+
The following examples work in both `doc_for` blocks and `doc` blocks.
|
|
231
|
+
|
|
232
|
+
### Request bodies
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
doc_for :create do
|
|
236
|
+
summary "Create a user"
|
|
237
|
+
tags "Users"
|
|
238
|
+
|
|
239
|
+
request_body required: true do
|
|
240
|
+
property :email, type: :string, required: true, example: "user@example.com"
|
|
241
|
+
property :password, type: :string, required: true, format: :password
|
|
242
|
+
property :name, type: :string, example: "Jane Doe"
|
|
243
|
+
property :profile, type: :object do
|
|
244
|
+
property :bio, type: :string
|
|
245
|
+
property :avatar_url, type: :string, format: :uri
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
response 201, "User created" do
|
|
250
|
+
property :id, type: :integer, example: 1
|
|
251
|
+
property :email, type: :string, example: "user@example.com"
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
response 422, "Validation failed" do
|
|
255
|
+
property :errors, type: :object do
|
|
256
|
+
property :email, type: :array, items: :string
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
def create
|
|
261
|
+
# your code
|
|
262
|
+
end
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Path parameters
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
doc_for :show do
|
|
269
|
+
summary "Get a user"
|
|
270
|
+
tags "Users"
|
|
271
|
+
|
|
272
|
+
parameter :id, location: :path, type: :integer, required: true, description: "User ID"
|
|
273
|
+
|
|
274
|
+
response 200, "User found" do
|
|
275
|
+
property :id, type: :integer, example: 1
|
|
276
|
+
property :email, type: :string
|
|
277
|
+
property :name, type: :string
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
response 404, "User not found" do
|
|
281
|
+
property :error, type: :string, example: "Not found"
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
def show
|
|
285
|
+
# your code
|
|
286
|
+
end
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Enums
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
292
|
+
doc_for :index do
|
|
293
|
+
summary "List orders"
|
|
294
|
+
tags "Orders"
|
|
295
|
+
|
|
296
|
+
parameter :status, location: :query, type: :string,
|
|
297
|
+
enum: %w[pending shipped delivered],
|
|
298
|
+
description: "Filter by status"
|
|
299
|
+
|
|
300
|
+
response 200, "Orders list" do
|
|
301
|
+
property :orders, type: :array do
|
|
302
|
+
property :id, type: :integer
|
|
303
|
+
property :status, type: :string, enum: %w[pending shipped delivered]
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Property options
|
|
310
|
+
|
|
311
|
+
Any `property` (in a request body, response, or shared schema) accepts these OpenAPI 3.0.3 options:
|
|
312
|
+
|
|
313
|
+
```ruby
|
|
314
|
+
request_body required: true do
|
|
315
|
+
property :id, type: :integer, read_only: true # readOnly: present in responses, not accepted as input
|
|
316
|
+
property :password, type: :string, write_only: true # writeOnly: accepted as input, never returned
|
|
317
|
+
property :role, type: :string, default: "member" # default value
|
|
318
|
+
property :nickname, type: :string, nullable: true # may be null
|
|
319
|
+
property :active, type: :boolean, default: false # falsy defaults are preserved
|
|
320
|
+
end
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
These map to `readOnly`, `writeOnly`, `default`, and `nullable` in the generated spec.
|
|
324
|
+
|
|
325
|
+
### Response headers
|
|
326
|
+
|
|
327
|
+
Document the headers a response returns with `header` inside a `response` block:
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
response 200, "Orders list" do
|
|
331
|
+
header "X-Total-Count", type: :integer, description: "Total orders available"
|
|
332
|
+
header "X-RateLimit-Remaining", type: :integer, description: "Requests left in the window"
|
|
333
|
+
|
|
334
|
+
property :orders, type: :array do
|
|
335
|
+
property :id, type: :integer
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Security
|
|
341
|
+
|
|
342
|
+
Mark endpoints as requiring authentication:
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
doc_for :destroy do
|
|
346
|
+
summary "Delete a user"
|
|
347
|
+
tags "Users"
|
|
348
|
+
security :bearer_auth # references the scheme from your config
|
|
349
|
+
|
|
350
|
+
response 204, "User deleted"
|
|
351
|
+
response 401, "Unauthorized"
|
|
352
|
+
end
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Deprecated endpoints
|
|
356
|
+
|
|
357
|
+
```ruby
|
|
358
|
+
doc_for :legacy_search do
|
|
359
|
+
summary "Search (legacy)"
|
|
360
|
+
tags "Search"
|
|
361
|
+
deprecated
|
|
362
|
+
|
|
363
|
+
response 200, "Results"
|
|
364
|
+
end
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Nested objects and arrays
|
|
368
|
+
|
|
369
|
+
```ruby
|
|
370
|
+
response 200, "Success" do
|
|
371
|
+
property :user, type: :object do
|
|
372
|
+
property :id, type: :integer
|
|
373
|
+
property :name, type: :string
|
|
374
|
+
property :addresses, type: :array do
|
|
375
|
+
property :street, type: :string
|
|
376
|
+
property :city, type: :string
|
|
377
|
+
property :zip, type: :string
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Response examples
|
|
384
|
+
|
|
385
|
+
```ruby
|
|
386
|
+
response 200, "User found" do
|
|
387
|
+
property :id, type: :integer
|
|
388
|
+
property :email, type: :string
|
|
389
|
+
|
|
390
|
+
example "admin_user",
|
|
391
|
+
{ id: 1, email: "admin@example.com" },
|
|
392
|
+
description: "An admin user"
|
|
393
|
+
|
|
394
|
+
example "regular_user",
|
|
395
|
+
{ id: 2, email: "user@example.com" },
|
|
396
|
+
description: "A regular user"
|
|
397
|
+
end
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Shared schemas (`$ref`)
|
|
401
|
+
|
|
402
|
+
Define reusable schemas once and reference them across multiple endpoints:
|
|
403
|
+
|
|
404
|
+
```ruby
|
|
405
|
+
# In config/initializers/docit.rb or a dedicated file:
|
|
406
|
+
Docit.define_schema :User do
|
|
407
|
+
property :id, type: :integer, example: 1
|
|
408
|
+
property :email, type: :string, example: "user@example.com"
|
|
409
|
+
property :name, type: :string, example: "Jane Doe"
|
|
410
|
+
property :address, type: :object do
|
|
411
|
+
property :street, type: :string
|
|
412
|
+
property :city, type: :string
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
Docit.define_schema :Error do
|
|
417
|
+
property :error, type: :string, example: "Not found"
|
|
418
|
+
property :details, type: :array, items: :string
|
|
419
|
+
end
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Reference them in any endpoint with `schema ref:`:
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
doc_for :show do
|
|
426
|
+
summary "Get user"
|
|
427
|
+
tags "Users"
|
|
428
|
+
|
|
429
|
+
response 200, "User found" do
|
|
430
|
+
schema ref: :User
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
response 404, "Not found" do
|
|
434
|
+
schema ref: :Error
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
doc_for :create do
|
|
439
|
+
summary "Create user"
|
|
440
|
+
tags "Users"
|
|
441
|
+
|
|
442
|
+
request_body required: true do
|
|
443
|
+
schema ref: :User
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
response 201, "Created" do
|
|
447
|
+
schema ref: :User
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
This outputs `$ref: '#/components/schemas/User'` in the spec — Swagger UI resolves it automatically.
|
|
453
|
+
|
|
454
|
+
### File uploads
|
|
455
|
+
|
|
456
|
+
Use `type: :file` with `content_type: "multipart/form-data"` for file upload endpoints:
|
|
457
|
+
|
|
458
|
+
```ruby
|
|
459
|
+
doc_for :upload_avatar do
|
|
460
|
+
summary "Upload avatar"
|
|
461
|
+
tags "Users"
|
|
462
|
+
|
|
463
|
+
request_body required: true, content_type: "multipart/form-data" do
|
|
464
|
+
property :avatar, type: :file, required: true, description: "Avatar image"
|
|
465
|
+
property :caption, type: :string
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
response 201, "Avatar uploaded" do
|
|
469
|
+
property :url, type: :string, format: :uri
|
|
470
|
+
end
|
|
116
471
|
end
|
|
117
472
|
```
|
|
118
473
|
|
|
119
|
-
|
|
474
|
+
`type: :file` maps to `{ type: "string", format: "binary" }` in the OpenAPI spec.
|
|
475
|
+
|
|
476
|
+
## AI Automatic Documentation
|
|
477
|
+
|
|
478
|
+
Docit can generate complete API documentation using AI. This works with OpenAI, Anthropic, or Groq (free tier available).
|
|
120
479
|
|
|
121
|
-
|
|
480
|
+
### Quick start (included in install)
|
|
122
481
|
|
|
123
|
-
|
|
482
|
+
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.
|
|
124
483
|
|
|
125
|
-
|
|
484
|
+
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.
|
|
485
|
+
|
|
486
|
+
### Standalone commands
|
|
487
|
+
|
|
488
|
+
You can also set up AI docs separately:
|
|
126
489
|
|
|
127
490
|
```bash
|
|
128
|
-
#
|
|
491
|
+
# Configure your AI provider (one-time setup)
|
|
129
492
|
rails generate docit:ai_setup
|
|
493
|
+
|
|
494
|
+
# Generate docs for all undocumented endpoints
|
|
130
495
|
rails docit:autodoc
|
|
131
496
|
|
|
132
|
-
#
|
|
497
|
+
# Generate docs for a specific controller
|
|
498
|
+
rails docit:autodoc[Api::V1::UsersController]
|
|
499
|
+
|
|
500
|
+
# Preview what would be generated without writing files
|
|
133
501
|
DRY_RUN=1 rails docit:autodoc
|
|
134
502
|
```
|
|
135
503
|
|
|
136
|
-
|
|
504
|
+
### Supported providers
|
|
505
|
+
|
|
506
|
+
| Provider | Notes |
|
|
507
|
+
|------------|-------|
|
|
508
|
+
| OpenAI | Requires API key from platform.openai.com |
|
|
509
|
+
| Anthropic | Requires API key from console.anthropic.com |
|
|
510
|
+
| Groq | Free tier at console.groq.com |
|
|
511
|
+
|
|
512
|
+
All providers automatically retry on rate-limit (429) errors with exponential backoff, so free-tier usage works out of the box.
|
|
513
|
+
|
|
514
|
+
AI configuration is stored in `.docit_ai.yml`.
|
|
515
|
+
If your app does not have a `.gitignore`, add `.docit_ai.yml` manually.
|
|
516
|
+
|
|
517
|
+
### What the AI generates
|
|
518
|
+
|
|
519
|
+
For each undocumented endpoint, Docit:
|
|
520
|
+
|
|
521
|
+
1. Reads the controller source code
|
|
522
|
+
2. Inspects the route (HTTP method, path, parameters)
|
|
523
|
+
3. Writes the generated doc block to `app/docs/`
|
|
524
|
+
4. Injects `use_docs` into the controller
|
|
525
|
+
5. Adds tag descriptions to the initializer
|
|
526
|
+
|
|
527
|
+
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.
|
|
137
528
|
|
|
138
529
|
## Documentation UIs
|
|
139
530
|
|
|
531
|
+
Docit ships with two documentation UIs, both reading from the same OpenAPI spec:
|
|
532
|
+
|
|
140
533
|
| Path | UI | Notes |
|
|
141
534
|
|------|------|-------|
|
|
142
535
|
| `/api-docs` | Default (Scalar) | Configurable via `config.default_ui` |
|
|
143
|
-
| `/api-docs/scalar` | Scalar API Reference | Modern UI with API client, dark mode |
|
|
536
|
+
| `/api-docs/scalar` | Scalar API Reference | Modern UI with built-in API client, dark mode, code samples |
|
|
144
537
|
| `/api-docs/swagger` | Swagger UI | Classic OpenAPI explorer |
|
|
538
|
+
| `/api-docs/system` | System Map | Local architecture graph for routes, controllers, docs coverage, and app structure |
|
|
145
539
|
| `/api-docs/spec` | Raw JSON | OpenAPI 3.0.3 spec |
|
|
146
540
|
|
|
147
|
-
|
|
541
|
+
Both UIs include a navigation bar to switch between them. Set `config.default_ui = :swagger` to make Swagger the default at `/api-docs`.
|
|
542
|
+
|
|
543
|
+
## System Map
|
|
544
|
+
|
|
545
|
+
Docit includes a local system map for understanding how your Rails API fits together. It builds a **deterministic** graph from Rails routes, controller actions, Docit docs, schemas, models, and source references — no external service is required to view it.
|
|
546
|
+
|
|
547
|
+
Visit `/api-docs/system` to open it. It has two views, a light/dark theme toggle, and PNG export:
|
|
548
|
+
|
|
549
|
+
- **Diagram** — an interactive architecture graph. Drag nodes to rearrange, scroll to zoom, and click a node to inspect its connections (its neighbours highlight while the rest fade back). Filter to a single resource with the section dropdown, or press `/` to search nodes.
|
|
550
|
+
- **Docs** — a request/response reference grouped by resource. Each endpoint shows a human-readable title, its method and path, parameters, request body, and responses, drawn from your Docit docs. A coverage indicator shows how many endpoints in each section are documented.
|
|
551
|
+
|
|
552
|
+
If you have an AI provider configured, the Docs view's **Explain section** button summarises how a resource's endpoints work together. It warns before running on sections with undocumented endpoints, so documenting first gives a better result.
|
|
553
|
+
|
|
554
|
+
## How it works
|
|
148
555
|
|
|
149
556
|
1. `doc_for` registers an **Operation** for each controller action in a global **Registry**
|
|
150
557
|
2. 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
|
|
151
558
|
3. The **Engine** serves the configured documentation UI at `/api-docs`, pointing it at the generated spec
|
|
559
|
+
4. The **SystemGraph** builds a local architecture graph for `/api-docs/system`
|
|
560
|
+
|
|
561
|
+
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`.
|
|
562
|
+
|
|
563
|
+
## Mounting at a different path
|
|
564
|
+
|
|
565
|
+
In `config/routes.rb`:
|
|
566
|
+
|
|
567
|
+
```ruby
|
|
568
|
+
mount Docit::Engine => "/docs" # now at /docs instead of /api-docs
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Restricting access in production
|
|
572
|
+
|
|
573
|
+
The Docit endpoints (`/api-docs`, `/api-docs/spec`, `/api-docs/system`, `/api-docs/system.json`) are **unauthenticated by default** and expose your full API surface, the OpenAPI spec, and — for the System Map — your app's structure and source file paths. That is convenient in development, but in production you almost always want to gate them.
|
|
574
|
+
|
|
575
|
+
Mount the engine inside an authenticated constraint, or behind whatever auth your app already uses:
|
|
576
|
+
|
|
577
|
+
```ruby
|
|
578
|
+
# config/routes.rb
|
|
579
|
+
|
|
580
|
+
# Option A — only mount outside production
|
|
581
|
+
mount Docit::Engine => "/api-docs" unless Rails.env.production?
|
|
582
|
+
|
|
583
|
+
# Option B — gate behind an authenticated constraint (e.g. Devise admins)
|
|
584
|
+
authenticate :user, ->(u) { u.admin? } do
|
|
585
|
+
mount Docit::Engine => "/api-docs"
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
# Option C — HTTP Basic auth via a Rack constraint
|
|
589
|
+
admins_only = ->(request) do
|
|
590
|
+
ActiveSupport::SecurityUtils.secure_compare(
|
|
591
|
+
request.authorization.to_s, ENV.fetch("DOCS_AUTH", "")
|
|
592
|
+
)
|
|
593
|
+
end
|
|
594
|
+
constraints(admins_only) { mount Docit::Engine => "/api-docs" }
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
If you disable the System Map specifically, set `config.system_graph_enabled = false` — `/api-docs/system.json` then returns `404`.
|
|
598
|
+
|
|
599
|
+
## JSON spec only
|
|
600
|
+
|
|
601
|
+
If you just want the raw OpenAPI JSON (e.g., for code generation):
|
|
602
|
+
|
|
603
|
+
```
|
|
604
|
+
GET /api-docs/spec
|
|
605
|
+
```
|
|
152
606
|
|
|
153
607
|
## Development
|
|
154
608
|
|
|
@@ -156,7 +610,7 @@ See the [full AI documentation guide](https://docitruby.dev/docs/ai-documentatio
|
|
|
156
610
|
git clone https://github.com/S13G/docit.git
|
|
157
611
|
cd docit
|
|
158
612
|
bundle install
|
|
159
|
-
bundle exec rspec
|
|
613
|
+
bundle exec rspec # run all tests
|
|
160
614
|
```
|
|
161
615
|
|
|
162
616
|
## Contributing
|
data/TROUBLESHOOTING.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Common questions and fixes when working with Docit.
|
|
4
|
+
|
|
5
|
+
## My route isn't showing up in the spec
|
|
6
|
+
|
|
7
|
+
Docit only documents an endpoint if **both** are true:
|
|
8
|
+
|
|
9
|
+
1. The route exists in `config/routes.rb` (visible in `rails routes`).
|
|
10
|
+
2. A doc is registered for that controller + action — either inline with `doc_for :action do ... end` or via `use_docs SomeDocs`.
|
|
11
|
+
|
|
12
|
+
A route with no matching `doc_for`/`use_docs` is simply absent from `/api-docs/spec`. It will still appear on the **System Map** (`/api-docs/system`) marked `undocumented`, which is the quickest way to see your coverage gaps.
|
|
13
|
+
|
|
14
|
+
Checklist:
|
|
15
|
+
|
|
16
|
+
- Is the action name spelled exactly the same in the route and in `doc_for`?
|
|
17
|
+
- Is the controller actually loaded? Docit eager-loads controllers when generating the spec, but a controller in a non-standard path may be missed.
|
|
18
|
+
- If using `use_docs`, does the doc module define a `doc :action` block for that action?
|
|
19
|
+
|
|
20
|
+
## A doc_for option seems to be ignored
|
|
21
|
+
|
|
22
|
+
Docit's DSL methods are explicit. If you mistype one (e.g. `summmary` instead of `summary`), the call currently does nothing rather than raising — so the option silently disappears.
|
|
23
|
+
|
|
24
|
+
Double-check the spelling of DSL methods against the [DSL reference in the README](README.md). The supported response/property options include `summary`, `description`, `tags`, `response`, `request_body`, `parameter`, `property` (with `type`, `format`, `example`, `enum`, `default`, `nullable`, `read_only`, `write_only`), `header`, `schema ref:`, `security`, `deprecated`, and `operation_id`.
|
|
25
|
+
|
|
26
|
+
## A System Map section says "undocumented" or shows low coverage
|
|
27
|
+
|
|
28
|
+
That section's endpoints have no registered docs. Add `doc_for`/`use_docs` for those actions, or accept the gap — coverage is informational, not an error.
|
|
29
|
+
|
|
30
|
+
## Schemas aren't linked on the System Map
|
|
31
|
+
|
|
32
|
+
`uses_schema` edges only appear when a documented endpoint references a shared schema with `schema ref: :Name` (in its request body or a response), and that schema is defined with `Docit.define_schema :Name`. A plain inline `property` block does not create a schema node.
|
|
33
|
+
|
|
34
|
+
## I documented an action twice and my changes are ignored
|
|
35
|
+
|
|
36
|
+
Docit's registry keeps the **first** doc registered for a given controller + action and ignores later ones. So if an action is already documented (e.g. via `use_docs SomeDocs`) and you also add an inline `doc_for :same_action do ... end`, the inline block is silently dropped — the `use_docs` version wins.
|
|
37
|
+
|
|
38
|
+
Document each action in exactly one place. If you need to override a shared doc module for one action, change it in the module rather than re-declaring it on the controller.
|
|
39
|
+
|
|
40
|
+
## AI autodoc / scaffolding isn't working
|
|
41
|
+
|
|
42
|
+
- Run `rails generate docit:ai_setup` once to configure a provider (OpenAI, Anthropic, or Groq). The key is written to `.docit_ai.yml`, which the generator adds to `.gitignore` — **never commit it.**
|
|
43
|
+
- `rails docit:autodoc` sends controller **source code** to your configured provider. In an interactive terminal it asks for confirmation first; in a non-interactive context (CI, piping) it proceeds without prompting, so only run it where sending source is acceptable.
|
|
44
|
+
- Preview without writing files: `DRY_RUN=1 rails docit:autodoc`.
|
|
45
|
+
- Rate-limit / 429 errors are retried with backoff automatically; a persistent failure usually means an invalid key or an unsupported model name.
|
|
46
|
+
|
|
47
|
+
## The System Map or docs pages are exposed in production
|
|
48
|
+
|
|
49
|
+
The Docit endpoints are **unauthenticated by default**. They expose your API surface, the OpenAPI spec, and your app structure. In production, gate the engine — see [Restricting access in production](README.md#restricting-access-in-production) in the README. To disable the System Map specifically, set `config.system_graph_enabled = false`.
|
|
50
|
+
|
|
51
|
+
## Spec generation is slow on a large app
|
|
52
|
+
|
|
53
|
+
Generating the spec eager-loads controllers and walks every route. For very large apps this is a one-time cost per request; put the docs behind a cache or a non-production-only mount if it matters. The System Map graph is rebuilt per request — if that becomes a bottleneck, mount it behind auth and access it sparingly.
|
|
54
|
+
|
|
55
|
+
## Still stuck?
|
|
56
|
+
|
|
57
|
+
Open an issue at <https://github.com/S13G/docit/issues> with your Docit version, Rails version, and a minimal `doc_for` / route example.
|