api-regulator 0.1.27 → 1.0.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/Gemfile.lock +1 -1
- data/README.md +660 -90
- data/lib/api_regulator/api.rb +4 -3
- data/lib/api_regulator/configuration.rb +1 -1
- data/lib/api_regulator/dsl.rb +2 -1
- data/lib/api_regulator/open_api_generator.rb +2 -2
- data/lib/api_regulator/version.rb +1 -1
- data/lib/tasks/api_regulator_tasks.rake +102 -114
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bcf52fc47c491d424f53b82688cfa8a3f0b78b62460267f1ad81abcf695827d
|
4
|
+
data.tar.gz: 1bb55ea5e11bff7fce98874adf0ca5d79db2431eabf4cafdaaf2dec7b4bb6fa4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c872be90e74a524e316958afc1486464612854794ca86f0fe78aef6ea9a67bc1779870eecd7fc8750987e0a5f3b2ca5a99c7af6047add3f3fb83d0e86c326d8b
|
7
|
+
data.tar.gz: e55567f1b2c788bae49bb536aee0aa10e9f6fa6c490ec04632c42a0b6acb0fb2758c54ef6c7944806aeb3453c197cf2bce749977c324d523dbca1c88eb19bf44
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,25 +1,21 @@
|
|
1
1
|
# ApiRegulator
|
2
2
|
|
3
|
-
ApiRegulator is a Ruby gem designed to **document** and **
|
3
|
+
ApiRegulator is a Ruby gem designed to **document**, **validate**, and **generate OpenAPI schemas** for Rails APIs. It provides a clean, Rails-friendly DSL for defining API endpoints, parameter validations, response schemas, and webhook definitions directly in your controllers, while automatically generating OpenAPI 3.1.0-compliant documentation.
|
4
4
|
|
5
|
-
ApiRegulator
|
5
|
+
ApiRegulator leverages **Active Model validations** for parameter validation, making it familiar and intuitive for Rails developers.
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
9
|
-
-
|
10
|
-
|
11
|
-
|
12
|
-
-
|
13
|
-
|
14
|
-
|
15
|
-
-
|
16
|
-
|
17
|
-
|
18
|
-
-
|
19
|
-
Share common response schemas across multiple endpoints for DRY definitions.
|
20
|
-
|
21
|
-
## ToDo
|
22
|
-
- [ ] Handling of extra undocumented params
|
9
|
+
- **🎯 API Documentation DSL**: Define API endpoints, request parameters, and response schemas using an intuitive, Rails-friendly DSL
|
10
|
+
- **✅ Dynamic Request Validation**: Automatically validate incoming requests against defined parameters using Active Model validations
|
11
|
+
- **📖 OpenAPI 3.1.0 Generation**: Generate fully compliant OpenAPI documentation ready for Swagger, Postman, or ReadMe
|
12
|
+
- **🔗 Webhook Documentation**: Define and document webhook payloads with the same DSL
|
13
|
+
- **🏷️ API Versioning**: Support multiple API versions with selective parameter inclusion
|
14
|
+
- **🔒 Security Schemes**: Define authentication and authorization schemes
|
15
|
+
- **🔄 Shared Schemas**: Reuse common response and parameter schemas across multiple endpoints
|
16
|
+
- **📚 ReadMe Integration**: Built-in tasks for generating OpenAPI specs and seamless integration with rdme CLI for uploading to ReadMe.com
|
17
|
+
- **🛡️ Parameter Validation**: Strict validation with helpful error messages for unexpected parameters
|
18
|
+
- **📄 Custom Page Management**: Upload and manage documentation pages alongside API specs
|
23
19
|
|
24
20
|
## Installation
|
25
21
|
|
@@ -31,131 +27,705 @@ gem 'api_regulator'
|
|
31
27
|
|
32
28
|
Run `bundle install` to install the gem.
|
33
29
|
|
30
|
+
### Optional: Install rdme CLI for ReadMe Integration
|
34
31
|
|
35
|
-
|
32
|
+
For uploading documentation to ReadMe, install the rdme CLI:
|
36
33
|
|
37
|
-
|
34
|
+
```bash
|
35
|
+
npm install -g rdme
|
36
|
+
```
|
38
37
|
|
39
|
-
|
38
|
+
Or as a project dependency:
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
config.docs_path = Rails.root.join("doc").to_s # Path for folder for docs
|
45
|
-
config.app_name = "My API" # shows in docs
|
40
|
+
```bash
|
41
|
+
npm install rdme --save-dev
|
42
|
+
```
|
46
43
|
|
47
|
-
|
48
|
-
config.versions = {
|
49
|
-
"v1.0" => "abc123",
|
50
|
-
"v1.0-internal" => "abc345"
|
51
|
-
}
|
52
|
-
config.default_version = "v1.0-internal"
|
44
|
+
## Setup
|
53
45
|
|
54
|
-
|
55
|
-
{ url: "https://stg.example.com", description: "Staging", "x-default": true },
|
56
|
-
{ url: "https://example.com", description: "Production" }
|
57
|
-
]
|
58
|
-
end
|
59
|
-
```
|
46
|
+
### 1. Create an Initializer
|
60
47
|
|
61
|
-
|
48
|
+
Add the following to `config/initializers/api_regulator.rb`:
|
62
49
|
|
63
|
-
|
50
|
+
```ruby
|
51
|
+
ApiRegulator.configure do |config|
|
52
|
+
config.api_base_url = "/api/v1"
|
53
|
+
config.docs_path = Rails.root.join("doc").to_s
|
54
|
+
config.app_name = "My API"
|
55
|
+
|
56
|
+
# Optional: Configure multiple API versions
|
57
|
+
config.versions = {
|
58
|
+
"v1.0" => "abc123", # ReadMe API spec ID
|
59
|
+
"v1.0-internal" => "abc345" # Internal version
|
60
|
+
}
|
61
|
+
config.default_version = "v1.0-internal"
|
62
|
+
|
63
|
+
# Optional: Define API servers
|
64
|
+
config.servers = [
|
65
|
+
{ url: "https://stg.example.com", description: "Staging", "x-default": true },
|
66
|
+
{ url: "https://example.com", description: "Production" }
|
67
|
+
]
|
68
|
+
end
|
69
|
+
```
|
64
70
|
|
65
|
-
|
66
|
-
class Api::ApplicationController < ActionController::API
|
67
|
-
include ApiRegulator::DSL
|
68
|
-
include ApiRegulator::ControllerMixin
|
69
|
-
end
|
70
|
-
```
|
71
|
+
### 2. Include the DSL in Your Base Controller
|
71
72
|
|
72
|
-
|
73
|
+
```ruby
|
74
|
+
class Api::ApplicationController < ActionController::API
|
75
|
+
include ApiRegulator::DSL
|
76
|
+
include ApiRegulator::ControllerMixin
|
77
|
+
end
|
78
|
+
```
|
73
79
|
|
74
|
-
|
80
|
+
### 3. Define Security Schemes (Optional)
|
75
81
|
|
76
|
-
|
82
|
+
```ruby
|
83
|
+
# In your initializer
|
84
|
+
ApiRegulator.security_schemes = {
|
85
|
+
bearer_auth: {
|
86
|
+
type: "http",
|
87
|
+
scheme: "bearer",
|
88
|
+
bearerFormat: "JWT"
|
89
|
+
},
|
90
|
+
api_key: {
|
91
|
+
type: "apiKey",
|
92
|
+
in: "header",
|
93
|
+
name: "X-API-Key"
|
94
|
+
}
|
95
|
+
}
|
96
|
+
```
|
97
|
+
|
98
|
+
## Usage
|
99
|
+
|
100
|
+
### Basic API Definition
|
77
101
|
|
78
102
|
```ruby
|
79
103
|
class Api::V1::CustomersController < Api::ApplicationController
|
80
|
-
api self, :create, "
|
104
|
+
api self, :create, desc: "Create a new customer", title: "Create Customer" do
|
105
|
+
# Path parameters
|
106
|
+
param :organization_id, :string, location: :path, presence: true
|
107
|
+
|
108
|
+
# Query parameters
|
109
|
+
param :expand, :string, location: :query, desc: "Comma-separated list of fields to expand"
|
110
|
+
|
111
|
+
# Body parameters
|
81
112
|
param :customer, presence: true do
|
82
113
|
param :first_name, :string, presence: true
|
83
114
|
param :last_name, :string, presence: true
|
84
|
-
param :email, :string, presence: true, format: { with:
|
85
|
-
param :ssn, :string, presence: true, length: {
|
115
|
+
param :email, :string, presence: true, format: { with: ApiRegulator::Formats::EMAIL }
|
116
|
+
param :ssn, :string, presence: true, length: { is: 9 }
|
117
|
+
param :date_of_birth, :string, format: { with: ApiRegulator::Formats::DATE }
|
118
|
+
|
119
|
+
# Nested objects
|
120
|
+
param :address, :object do
|
121
|
+
param :street, :string, presence: true
|
122
|
+
param :city, :string, presence: true
|
123
|
+
param :state, :string, presence: true, length: { is: 2 }
|
124
|
+
param :zip_code, :string, format: { with: ApiRegulator::Formats::ZIP_CODE }
|
125
|
+
end
|
126
|
+
|
127
|
+
# Arrays
|
128
|
+
param :phone_numbers, :array, item_type: :string
|
129
|
+
param :emergency_contacts, :array do
|
130
|
+
param :name, :string, presence: true
|
131
|
+
param :relationship, :string, presence: true
|
132
|
+
param :phone, :string, presence: true
|
133
|
+
end
|
86
134
|
end
|
87
135
|
|
88
|
-
|
136
|
+
# Response definitions
|
137
|
+
response 201, "Customer successfully created" do
|
89
138
|
param :customer do
|
90
|
-
param :id, :string, desc: "Customer
|
91
|
-
param :email, :string, desc: "Customer email"
|
139
|
+
param :id, :string, desc: "Customer UUID"
|
140
|
+
param :email, :string, desc: "Customer email address"
|
141
|
+
param :created_at, :string, desc: "ISO 8601 timestamp"
|
92
142
|
end
|
93
143
|
end
|
94
144
|
|
95
145
|
response 422, ref: :validation_errors
|
146
|
+
response 401, ref: :unauthorized_error
|
96
147
|
end
|
97
148
|
|
98
149
|
def create
|
99
|
-
validate_params! #
|
150
|
+
validate_params! # Validates against DSL definition
|
100
151
|
|
101
|
-
customer = Customer.create!(api_params[:customer])
|
102
|
-
render json: customer, status: :
|
152
|
+
customer = Customer.create!(api_params[:customer])
|
153
|
+
render json: { customer: customer }, status: :created
|
103
154
|
end
|
104
155
|
end
|
105
156
|
```
|
106
157
|
|
107
|
-
|
158
|
+
### Advanced Parameter Options
|
159
|
+
|
160
|
+
#### Conditional Requirements
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
param :ssn, :string, presence: {
|
164
|
+
required_on: [:create, :update], # Required only for these actions
|
165
|
+
required_except_on: [:show] # Required except for these actions
|
166
|
+
}
|
167
|
+
```
|
108
168
|
|
109
|
-
|
169
|
+
#### Version-Specific Parameters
|
110
170
|
|
111
171
|
```ruby
|
172
|
+
param :legacy_field, :string, versions: [:v1], desc: "Only available in v1"
|
173
|
+
param :new_feature, :boolean, versions: [:v2, :v3], desc: "Available in v2 and v3"
|
174
|
+
```
|
175
|
+
|
176
|
+
#### Type Validation and Formatting
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
param :age, :integer, numericality: { greater_than: 0, less_than: 150 }
|
180
|
+
param :website, :string, format: { with: ApiRegulator::Formats::URI }
|
181
|
+
param :score, :number, numericality: { greater_than_or_equal_to: 0.0, less_than_or_equal_to: 100.0 }
|
182
|
+
param :is_active, :boolean
|
183
|
+
param :tags, :array, item_type: :string, inclusion: { in: ["vip", "standard", "premium"] }
|
184
|
+
```
|
185
|
+
|
186
|
+
#### Arbitrary Keys Support
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
param :metadata, :object, allow_arbitrary_keys: true do
|
190
|
+
param :created_by, :string # Known fields can still be defined
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
#### Nullable Fields
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
param :middle_name, :string, presence: { allow_nil: true }
|
198
|
+
param :optional_date, :string, format: { with: ApiRegulator::Formats::DATE, allow_nil: true }
|
199
|
+
```
|
200
|
+
|
201
|
+
### Shared Schemas
|
202
|
+
|
203
|
+
Define reusable schemas in your initializer:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
# Common error responses
|
112
207
|
ApiRegulator.register_shared_schema :validation_errors, "Validation error response" do
|
113
|
-
param :errors, :array, desc: "Array of validation
|
208
|
+
param :errors, :array, desc: "Array of validation error messages" do
|
209
|
+
param :field, :string, desc: "Field name that failed validation"
|
210
|
+
param :message, :string, desc: "Human-readable error message"
|
211
|
+
param :code, :string, desc: "Error code for programmatic handling"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
ApiRegulator.register_shared_schema :unauthorized_error, "Authentication required" do
|
216
|
+
param :error, :string, desc: "Error message"
|
217
|
+
param :code, :integer, desc: "HTTP status code"
|
218
|
+
end
|
219
|
+
|
220
|
+
# Common response objects
|
221
|
+
ApiRegulator.register_shared_schema :pagination_meta, "Pagination metadata" do
|
222
|
+
param :current_page, :integer, desc: "Current page number"
|
223
|
+
param :per_page, :integer, desc: "Items per page"
|
224
|
+
param :total_pages, :integer, desc: "Total number of pages"
|
225
|
+
param :total_count, :integer, desc: "Total number of items"
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
Use shared schemas in your API definitions:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
api self, :index do
|
233
|
+
param :page, :integer, location: :query, desc: "Page number"
|
234
|
+
param :per_page, :integer, location: :query, desc: "Items per page"
|
235
|
+
|
236
|
+
response 200, "List of customers" do
|
237
|
+
param :customers, :array do
|
238
|
+
ref :customer_summary # Reference another shared schema
|
239
|
+
end
|
240
|
+
ref :pagination_meta
|
241
|
+
end
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
245
|
+
### Webhook Documentation
|
246
|
+
|
247
|
+
Define webhook payloads using the same DSL:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
class WebhookDefinitions < Api::ApplicationController
|
251
|
+
webhook :customer_created,
|
252
|
+
desc: "Fired when a new customer is created",
|
253
|
+
title: "Customer Created",
|
254
|
+
tags: ["customers", "webhooks"] do
|
255
|
+
|
256
|
+
param :event, :string, desc: "Event name"
|
257
|
+
param :timestamp, :string, desc: "ISO 8601 timestamp"
|
258
|
+
param :data do
|
259
|
+
param :customer do
|
260
|
+
param :id, :string, desc: "Customer UUID"
|
261
|
+
param :email, :string, desc: "Customer email"
|
262
|
+
param :created_at, :string, desc: "ISO 8601 timestamp"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
example :basic_example, {
|
267
|
+
event: "customer.created",
|
268
|
+
timestamp: "2024-01-15T10:30:00Z",
|
269
|
+
data: {
|
270
|
+
customer: {
|
271
|
+
id: "cust_abc123",
|
272
|
+
email: "john@example.com",
|
273
|
+
created_at: "2024-01-15T10:30:00Z"
|
274
|
+
}
|
275
|
+
}
|
276
|
+
}, default: true
|
277
|
+
end
|
278
|
+
end
|
279
|
+
```
|
280
|
+
|
281
|
+
### API Examples
|
282
|
+
|
283
|
+
Add examples to your API definitions:
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
api self, :create do
|
287
|
+
param :customer do
|
288
|
+
param :name, :string, presence: true
|
289
|
+
param :email, :string, presence: true
|
290
|
+
end
|
291
|
+
|
292
|
+
example :successful_creation, {
|
293
|
+
customer: {
|
294
|
+
name: "John Doe",
|
295
|
+
email: "john@example.com"
|
296
|
+
}
|
297
|
+
}, default: true
|
298
|
+
|
299
|
+
example :with_optional_fields, {
|
300
|
+
customer: {
|
301
|
+
name: "Jane Smith",
|
302
|
+
email: "jane@example.com",
|
303
|
+
phone: "+1-555-0123"
|
304
|
+
}
|
305
|
+
}
|
306
|
+
end
|
307
|
+
```
|
308
|
+
|
309
|
+
## Validation and Error Handling
|
310
|
+
|
311
|
+
### Automatic Parameter Validation
|
312
|
+
|
313
|
+
```ruby
|
314
|
+
def create
|
315
|
+
validate_params! # Raises ApiRegulator::InvalidParams or ApiRegulator::UnexpectedParams
|
316
|
+
|
317
|
+
# Access validated and type-converted parameters
|
318
|
+
customer_data = api_params[:customer]
|
319
|
+
# Process with confidence that data is valid
|
320
|
+
end
|
321
|
+
```
|
322
|
+
|
323
|
+
### Custom Error Handling
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
class Api::ApplicationController < ActionController::API
|
327
|
+
include ApiRegulator::DSL
|
328
|
+
include ApiRegulator::ControllerMixin
|
329
|
+
|
330
|
+
rescue_from ApiRegulator::InvalidParams do |exception|
|
331
|
+
render json: {
|
332
|
+
errors: exception.errors.messages,
|
333
|
+
message: "Validation failed"
|
334
|
+
}, status: :unprocessable_entity
|
335
|
+
end
|
336
|
+
|
337
|
+
rescue_from ApiRegulator::UnexpectedParams do |exception|
|
338
|
+
render json: {
|
339
|
+
errors: exception.details,
|
340
|
+
message: "Unexpected parameters provided"
|
341
|
+
}, status: :bad_request
|
342
|
+
end
|
343
|
+
end
|
344
|
+
```
|
345
|
+
|
346
|
+
## OpenAPI Documentation Generation
|
347
|
+
|
348
|
+
### Validate OpenAPI Specification
|
349
|
+
|
350
|
+
Before uploading, validate your OpenAPI specification using rdme:
|
351
|
+
|
352
|
+
```bash
|
353
|
+
# Validate the generated OpenAPI spec
|
354
|
+
rdme openapi validate doc/openapi.yaml
|
355
|
+
|
356
|
+
# Validate with specific version
|
357
|
+
rdme openapi validate doc/openapi.yaml --version=v1.0
|
358
|
+
```
|
359
|
+
|
360
|
+
### Generate Documentation
|
361
|
+
|
362
|
+
```bash
|
363
|
+
# Generate for default version
|
364
|
+
rake api_docs:generate
|
365
|
+
|
366
|
+
# Generate for specific version
|
367
|
+
VERSION=v1.0 rake api_docs:generate
|
368
|
+
|
369
|
+
# Generate for all configured versions
|
370
|
+
rake api_docs:generate_all
|
371
|
+
```
|
372
|
+
|
373
|
+
### Upload to ReadMe
|
374
|
+
|
375
|
+
ApiRegulator integrates with [rdme](https://github.com/readmeio/rdme), ReadMe's official CLI tool, for modern, secure, and reliable documentation management.
|
376
|
+
|
377
|
+
#### Installation
|
378
|
+
|
379
|
+
Install the rdme CLI globally:
|
380
|
+
|
381
|
+
```bash
|
382
|
+
npm install -g rdme
|
383
|
+
```
|
384
|
+
|
385
|
+
Or install it as a project dependency:
|
386
|
+
|
387
|
+
```bash
|
388
|
+
npm install rdme --save-dev
|
389
|
+
```
|
390
|
+
|
391
|
+
#### Authentication
|
392
|
+
|
393
|
+
Authenticate with ReadMe using the CLI:
|
394
|
+
|
395
|
+
```bash
|
396
|
+
rdme login
|
397
|
+
```
|
398
|
+
|
399
|
+
Alternatively, set your API key as an environment variable:
|
400
|
+
|
401
|
+
```bash
|
402
|
+
export RDME_API_KEY="your_readme_api_key"
|
403
|
+
```
|
404
|
+
|
405
|
+
#### Upload Commands
|
406
|
+
|
407
|
+
**Recommended approach using rdme CLI:**
|
408
|
+
|
409
|
+
```bash
|
410
|
+
# Generate and upload everything using rdme (RECOMMENDED)
|
411
|
+
rake api_docs:publish_rdme
|
412
|
+
|
413
|
+
# Or step by step:
|
414
|
+
rake api_docs:generate
|
415
|
+
rake api_docs:upload_rdme
|
416
|
+
rdme docs upload doc/
|
417
|
+
```
|
418
|
+
|
419
|
+
**Legacy approach (may not work with ReadMe API v2):**
|
420
|
+
|
421
|
+
```bash
|
422
|
+
# Generate OpenAPI specification
|
423
|
+
rake api_docs:generate
|
424
|
+
|
425
|
+
# Upload using legacy rake tasks (deprecated)
|
426
|
+
rake api_docs:upload
|
427
|
+
rake api_docs:upload_pages
|
428
|
+
```
|
429
|
+
|
430
|
+
#### Migration from Legacy Tasks
|
431
|
+
|
432
|
+
If you're experiencing 404 errors with the legacy upload tasks, migrate to rdme CLI:
|
433
|
+
|
434
|
+
```bash
|
435
|
+
# Run the migration script
|
436
|
+
./scripts/migrate_to_rdme.sh
|
437
|
+
|
438
|
+
# Or manually:
|
439
|
+
npm install -g rdme
|
440
|
+
rdme login
|
441
|
+
rake api_docs:publish_rdme
|
442
|
+
```
|
443
|
+
|
444
|
+
**rdme CLI Features:**
|
445
|
+
|
446
|
+
- Modern ReadMe API v2 integration
|
447
|
+
- Bearer token authentication (more secure)
|
448
|
+
- Better performance and reliability
|
449
|
+
- Support for ReadMe Refactored features
|
450
|
+
- Branch-based versioning
|
451
|
+
- Built-in validation and error handling
|
452
|
+
|
453
|
+
### Custom Documentation Pages
|
454
|
+
|
455
|
+
Create markdown files in your `docs_path` with YAML frontmatter:
|
456
|
+
|
457
|
+
```markdown
|
458
|
+
---
|
459
|
+
title: "Getting Started"
|
460
|
+
slug: "getting-started"
|
461
|
+
category: "documentation"
|
462
|
+
hidden: false
|
463
|
+
---
|
464
|
+
|
465
|
+
# Getting Started
|
466
|
+
|
467
|
+
Your API documentation content here...
|
468
|
+
```
|
469
|
+
|
470
|
+
### GitHub Actions Integration
|
471
|
+
|
472
|
+
Use rdme in your GitHub Actions workflow for automated documentation updates:
|
473
|
+
|
474
|
+
```yaml
|
475
|
+
name: Update API Documentation
|
476
|
+
|
477
|
+
on:
|
478
|
+
push:
|
479
|
+
branches: [main]
|
480
|
+
pull_request:
|
481
|
+
branches: [main]
|
482
|
+
|
483
|
+
jobs:
|
484
|
+
update-docs:
|
485
|
+
runs-on: ubuntu-latest
|
486
|
+
|
487
|
+
steps:
|
488
|
+
- name: Checkout code
|
489
|
+
uses: actions/checkout@v4
|
490
|
+
|
491
|
+
- name: Setup Ruby
|
492
|
+
uses: ruby/setup-ruby@v1
|
493
|
+
with:
|
494
|
+
ruby-version: 3.0
|
495
|
+
|
496
|
+
- name: Install dependencies
|
497
|
+
run: |
|
498
|
+
gem install bundler
|
499
|
+
bundle install
|
500
|
+
|
501
|
+
- name: Generate and upload API documentation
|
502
|
+
run: rake api_docs:publish_rdme
|
503
|
+
env:
|
504
|
+
RDME_API_KEY: ${{ secrets.RDME_API_KEY }}
|
505
|
+
```
|
506
|
+
|
507
|
+
### ReadMe Integration Features
|
508
|
+
|
509
|
+
```bash
|
510
|
+
# Validate OpenAPI specification
|
511
|
+
rdme openapi validate doc/openapi.yaml
|
512
|
+
|
513
|
+
# Upload OpenAPI spec using rake task (recommended)
|
514
|
+
rake api_docs:upload_rdme
|
515
|
+
|
516
|
+
# Upload with specific version
|
517
|
+
VERSION=v2.0 rake api_docs:upload_rdme
|
518
|
+
|
519
|
+
# Upload directly with rdme CLI
|
520
|
+
rdme openapi upload doc/openapi.yaml --version=v2.0
|
521
|
+
|
522
|
+
# Fetch available categories
|
523
|
+
rdme categories list
|
524
|
+
```
|
525
|
+
|
526
|
+
## Built-in Format Validators
|
527
|
+
|
528
|
+
ApiRegulator includes common format validators:
|
529
|
+
|
530
|
+
```ruby
|
531
|
+
ApiRegulator::Formats::DATE # ISO 8601 date format
|
532
|
+
ApiRegulator::Formats::DATETIME # ISO 8601 datetime format
|
533
|
+
ApiRegulator::Formats::EMAIL # Email address validation
|
534
|
+
ApiRegulator::Formats::ZIP_CODE # US ZIP code (12345 or 12345-6789)
|
535
|
+
ApiRegulator::Formats::URI # URI format validation
|
536
|
+
```
|
537
|
+
|
538
|
+
Usage example:
|
539
|
+
|
540
|
+
```ruby
|
541
|
+
param :email, :string, format: { with: ApiRegulator::Formats::EMAIL }
|
542
|
+
param :website, :string, format: { with: ApiRegulator::Formats::URI }
|
543
|
+
param :birth_date, :string, format: { with: ApiRegulator::Formats::DATE }
|
544
|
+
```
|
545
|
+
|
546
|
+
## Testing Your APIs
|
547
|
+
|
548
|
+
ApiRegulator integrates seamlessly with RSpec:
|
549
|
+
|
550
|
+
```ruby
|
551
|
+
RSpec.describe Api::V1::CustomersController do
|
552
|
+
describe "POST /api/v1/customers" do
|
553
|
+
it "validates required parameters" do
|
554
|
+
post "/api/v1/customers", params: {}
|
555
|
+
expect(response).to have_http_status(:unprocessable_entity)
|
556
|
+
end
|
557
|
+
|
558
|
+
it "creates customer with valid parameters" do
|
559
|
+
params = {
|
560
|
+
customer: {
|
561
|
+
first_name: "John",
|
562
|
+
last_name: "Doe",
|
563
|
+
email: "john@example.com"
|
564
|
+
}
|
565
|
+
}
|
566
|
+
|
567
|
+
post "/api/v1/customers", params: params
|
568
|
+
expect(response).to have_http_status(:created)
|
569
|
+
end
|
570
|
+
end
|
571
|
+
end
|
572
|
+
```
|
573
|
+
|
574
|
+
## Configuration Reference
|
575
|
+
|
576
|
+
```ruby
|
577
|
+
ApiRegulator.configure do |config|
|
578
|
+
# Base URL for all API endpoints (default: "api/v1")
|
579
|
+
config.api_base_url = "/api/v1"
|
580
|
+
|
581
|
+
# Application name shown in documentation (default: "API Documentation")
|
582
|
+
config.app_name = "My API"
|
583
|
+
|
584
|
+
# Directory for documentation files (default: "doc")
|
585
|
+
config.docs_path = Rails.root.join("doc").to_s
|
586
|
+
|
587
|
+
# Version mapping for ReadMe (optional)
|
588
|
+
config.versions = {
|
589
|
+
"v1.0" => "readme_spec_id_1",
|
590
|
+
"v2.0" => "readme_spec_id_2"
|
591
|
+
}
|
592
|
+
|
593
|
+
# Default version when none specified (optional)
|
594
|
+
config.default_version = "v1.0"
|
595
|
+
|
596
|
+
# Server definitions for OpenAPI spec (optional)
|
597
|
+
config.servers = [
|
598
|
+
{ url: "https://api.example.com", description: "Production" },
|
599
|
+
{ url: "https://staging-api.example.com", description: "Staging" }
|
600
|
+
]
|
601
|
+
end
|
602
|
+
```
|
603
|
+
|
604
|
+
## Advanced Usage
|
605
|
+
|
606
|
+
### Multiple API Versions
|
607
|
+
|
608
|
+
```ruby
|
609
|
+
# Define version-specific endpoints
|
610
|
+
api self, :create, versions: [:v1, :v2] do
|
611
|
+
param :name, :string, presence: true
|
612
|
+
param :email, :string, presence: true, versions: [:v1, :v2]
|
613
|
+
param :phone, :string, versions: [:v2] # Only in v2
|
614
|
+
end
|
615
|
+
```
|
616
|
+
|
617
|
+
### Security Requirements
|
618
|
+
|
619
|
+
```ruby
|
620
|
+
api self, :create do
|
621
|
+
# This endpoint requires authentication
|
622
|
+
security [{ bearer_auth: [] }]
|
623
|
+
|
624
|
+
param :customer do
|
625
|
+
param :name, :string, presence: true
|
626
|
+
end
|
114
627
|
end
|
115
628
|
```
|
116
629
|
|
117
|
-
|
630
|
+
### Custom Validation Context
|
631
|
+
|
118
632
|
```ruby
|
119
|
-
|
633
|
+
def update
|
634
|
+
# Validate with specific context
|
635
|
+
validate_params!
|
636
|
+
|
637
|
+
# The validation context is automatically set to the action name (:update)
|
638
|
+
# This allows conditional validations based on the action
|
120
639
|
end
|
121
640
|
```
|
122
641
|
|
123
|
-
##
|
642
|
+
## Troubleshooting
|
643
|
+
|
644
|
+
### Common Issues
|
645
|
+
|
646
|
+
#### 404 Error When Uploading Pages
|
647
|
+
|
648
|
+
If you get a 404 error when uploading documentation pages:
|
649
|
+
|
650
|
+
```
|
651
|
+
Failed to upload page 'Webhooks'!
|
652
|
+
Response Code: 404
|
653
|
+
```
|
654
|
+
|
655
|
+
**Solution:** The legacy rake tasks may not work with ReadMe API v2. Use rdme CLI instead:
|
656
|
+
|
657
|
+
```bash
|
658
|
+
# Install and authenticate with rdme
|
659
|
+
npm install -g rdme
|
660
|
+
rdme login
|
661
|
+
|
662
|
+
# Use the recommended approach
|
663
|
+
rake api_docs:publish_rdme
|
664
|
+
```
|
665
|
+
|
666
|
+
#### Authentication Issues
|
667
|
+
|
668
|
+
If you get authentication errors:
|
669
|
+
|
670
|
+
```bash
|
671
|
+
# Check your authentication status
|
672
|
+
rdme whoami
|
673
|
+
|
674
|
+
# Re-authenticate if needed
|
675
|
+
rdme logout
|
676
|
+
rdme login
|
677
|
+
```
|
678
|
+
|
679
|
+
#### OpenAPI Validation Errors
|
680
|
+
|
681
|
+
Validate your OpenAPI spec before uploading:
|
682
|
+
|
683
|
+
```bash
|
684
|
+
# Validate the generated spec
|
685
|
+
rdme openapi validate doc/openapi.yaml
|
686
|
+
|
687
|
+
# Check for common issues
|
688
|
+
rdme openapi validate doc/openapi.yaml --verbose
|
689
|
+
```
|
690
|
+
|
691
|
+
## Error Reference
|
124
692
|
|
125
|
-
|
693
|
+
- `ApiRegulator::InvalidParams`: Raised when request parameters fail validation
|
694
|
+
- `ApiRegulator::UnexpectedParams`: Raised when unexpected parameters are provided
|
695
|
+
- `ApiRegulator::ValidationError`: Base class for validation errors
|
126
696
|
|
697
|
+
## Development and Contributing
|
127
698
|
|
128
|
-
1.
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
699
|
+
1. Fork the repository
|
700
|
+
2. Create your feature branch (`git checkout -b feature/new-feature`)
|
701
|
+
3. Write tests for your changes
|
702
|
+
4. Ensure all tests pass (`bundle exec rspec`)
|
703
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
704
|
+
6. Push to the branch (`git push origin feature/new-feature`)
|
705
|
+
7. Open a pull request
|
133
706
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
707
|
+
### Running Tests
|
708
|
+
|
709
|
+
```bash
|
710
|
+
bundle install
|
711
|
+
bundle exec rspec
|
712
|
+
```
|
139
713
|
|
140
|
-
|
141
|
-
```bash
|
142
|
-
rake api_docs:publish
|
143
|
-
```
|
714
|
+
## Releasing New Versions
|
144
715
|
|
145
|
-
|
146
|
-
1. Fork the repository.
|
147
|
-
2. Create your feature branch (git checkout -b feature/new-feature).
|
148
|
-
3. Commit your changes (git commit -am 'Add some feature').
|
149
|
-
4. Push to the branch (git push origin feature/new-feature).
|
150
|
-
5. Open a pull request.
|
716
|
+
ApiRegulator is published to [RubyGems](https://rubygems.org/gems/api-regulator). To release:
|
151
717
|
|
152
|
-
|
153
|
-
`
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
718
|
+
1. Update version in `lib/api_regulator/version.rb`
|
719
|
+
2. Run `bundle install` to update `Gemfile.lock`
|
720
|
+
3. Create PR and merge after review
|
721
|
+
4. Trigger the [Release Gem workflow](https://github.com/Stellarcred/api-regulator/actions/workflows/release.yml)
|
722
|
+
5. Verify publication on [RubyGems](https://rubygems.org/gems/api-regulator)
|
723
|
+
|
724
|
+
## Requirements
|
725
|
+
|
726
|
+
- Ruby >= 3.0
|
727
|
+
- Rails >= 8.0 (ActiveSupport and ActiveModel)
|
159
728
|
|
160
729
|
## License
|
730
|
+
|
161
731
|
This gem is available as open-source software under the [MIT License](https://mit-license.org/).
|
data/lib/api_regulator/api.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module ApiRegulator
|
2
2
|
class Api
|
3
3
|
attr_reader :controller_class, :controller_path, :controller_name, :action_name, :description,
|
4
|
-
:title, :params, :responses, :versions, :examples
|
4
|
+
:title, :params, :responses, :versions, :examples, :tags
|
5
5
|
|
6
|
-
def initialize(controller_class, action_name, desc: nil, title: nil, versions: [], &block)
|
6
|
+
def initialize(controller_class, action_name, desc: nil, title: nil, versions: [], tags: [], &block)
|
7
7
|
@controller_class = controller_class
|
8
8
|
@controller_name = controller_class.name
|
9
9
|
@controller_path = controller_class.controller_path
|
10
10
|
@action_name = action_name.to_s
|
11
11
|
@description = desc
|
12
12
|
@title = title
|
13
|
+
@tags = tags.presence || default_tags
|
13
14
|
@versions = Array(versions).map(&:to_sym)
|
14
15
|
|
15
16
|
@params = []
|
@@ -88,7 +89,7 @@ module ApiRegulator
|
|
88
89
|
"#{controller_path.gsub("/", "-")}-#{action_name}"
|
89
90
|
end
|
90
91
|
|
91
|
-
def
|
92
|
+
def default_tags
|
92
93
|
[
|
93
94
|
controller_name
|
94
95
|
.demodulize
|
data/lib/api_regulator/dsl.rb
CHANGED
@@ -9,7 +9,7 @@ module ApiRegulator
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module ClassMethods
|
12
|
-
def api(controller_class, action, desc: nil, title: nil, versions: [], &block)
|
12
|
+
def api(controller_class, action, desc: nil, title: nil, versions: [], tags: [], &block)
|
13
13
|
@api_definitions ||= []
|
14
14
|
|
15
15
|
api_definition = Api.new(
|
@@ -18,6 +18,7 @@ module ApiRegulator
|
|
18
18
|
desc: desc,
|
19
19
|
title: title,
|
20
20
|
versions: versions,
|
21
|
+
tags: tags,
|
21
22
|
&block
|
22
23
|
)
|
23
24
|
|
@@ -30,12 +30,12 @@ module ApiRegulator
|
|
30
30
|
openapi: '3.1.0', # Explicitly target OpenAPI 3.1.0
|
31
31
|
info: {
|
32
32
|
title: ApiRegulator.configuration.app_name,
|
33
|
-
description: 'Generated by ApiRegulator'
|
33
|
+
description: 'Generated by ApiRegulator',
|
34
|
+
version: version.presence || '1.0.0'
|
34
35
|
},
|
35
36
|
servers: ApiRegulator.configuration.servers,
|
36
37
|
paths: {}
|
37
38
|
}
|
38
|
-
final_schema[:info][:version] = version if version.present?
|
39
39
|
|
40
40
|
add_components
|
41
41
|
add_security
|
@@ -23,128 +23,116 @@ namespace :api_docs do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
desc "Upload OpenAPI schema to ReadMe"
|
27
|
-
task :
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
desc "Upload OpenAPI schema to ReadMe using rdme CLI (RECOMMENDED)"
|
27
|
+
task upload_rdme: :environment do
|
28
|
+
# Check if rdme is available
|
29
|
+
unless system("which rdme > /dev/null 2>&1")
|
30
|
+
puts "❌ rdme CLI not found. Please install it first:"
|
31
|
+
puts " npm install -g rdme"
|
32
|
+
puts " rdme login"
|
33
|
+
exit 1
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
schema_path =
|
36
|
+
version = ENV['VERSION'] || ApiRegulator.configuration.default_version
|
37
|
+
schema_path = ApiRegulator::OpenApiGenerator.schema_file_path(version: version)
|
38
|
+
|
37
39
|
unless File.exist?(schema_path)
|
38
|
-
raise "OpenAPI schema file not found at #{schema_path}"
|
40
|
+
raise "OpenAPI schema file not found at #{schema_path}. Run 'rake api_docs:generate' first."
|
39
41
|
end
|
40
|
-
openapi_content = File.read(schema_path)
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
puts "📄 Uploading OpenAPI specification with rdme CLI..."
|
44
|
+
puts " Schema: #{schema_path}"
|
45
|
+
puts " Version: #{version || 'default'}"
|
46
|
+
puts ""
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
# Use rdme CLI to upload
|
49
|
+
if system("rdme openapi upload #{schema_path}")
|
50
|
+
puts "✅ OpenAPI schema successfully uploaded!"
|
50
51
|
else
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
request["Authorization"] = "Basic #{Base64.strict_encode64(readme_api_key)}"
|
55
|
-
request["Content-Type"] = "application/json"
|
56
|
-
request["x-readme-version"] = version if version.present?
|
57
|
-
request.body = {
|
58
|
-
spec: JSON.parse(openapi_content)
|
59
|
-
}.to_json
|
60
|
-
|
61
|
-
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
62
|
-
http.request(request)
|
52
|
+
puts "❌ Failed to upload OpenAPI schema"
|
53
|
+
exit 1
|
63
54
|
end
|
55
|
+
end
|
64
56
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
57
|
+
desc "Upload OpenAPI schema to ReadMe (LEGACY - may not work with ReadMe API v2)"
|
58
|
+
task :upload => :environment do
|
59
|
+
puts "⚠️ WARNING: This rake task is deprecated and may not work with ReadMe API v2."
|
60
|
+
puts " Please use the rdme CLI instead:"
|
61
|
+
puts " "
|
62
|
+
puts " # Install rdme CLI"
|
63
|
+
puts " npm install -g rdme"
|
64
|
+
puts " "
|
65
|
+
puts " # Authenticate with ReadMe"
|
66
|
+
puts " rdme login"
|
67
|
+
puts " "
|
68
|
+
puts " # Upload using rdme CLI"
|
69
|
+
puts " rake api_docs:upload_rdme"
|
70
|
+
puts " "
|
71
|
+
puts " For more information, see: https://github.com/readmeio/rdme"
|
72
|
+
puts " "
|
73
|
+
|
74
|
+
# Check if rdme is available
|
75
|
+
if system("which rdme > /dev/null 2>&1")
|
76
|
+
puts "✅ rdme CLI is installed. Running: rake api_docs:upload_rdme"
|
77
|
+
Rake::Task["api_docs:upload_rdme"].invoke
|
75
78
|
else
|
76
|
-
puts "
|
77
|
-
puts "
|
78
|
-
|
79
|
-
pp JSON.parse(response.body)
|
79
|
+
puts "❌ rdme CLI not found. Please install it first:"
|
80
|
+
puts " npm install -g rdme"
|
81
|
+
exit 1
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
83
|
-
desc 'Generate and upload OpenAPI schema'
|
85
|
+
desc 'Generate and upload OpenAPI schema using rdme CLI (RECOMMENDED)'
|
86
|
+
task publish_rdme: :environment do
|
87
|
+
Rake::Task["api_docs:generate"].invoke
|
88
|
+
Rake::Task["api_docs:upload_rdme"].invoke
|
89
|
+
|
90
|
+
puts "📄 Uploading documentation pages with rdme CLI..."
|
91
|
+
system("rdme docs upload #{ApiRegulator.configuration.docs_path}/")
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'Generate and upload OpenAPI schema (LEGACY - may not work with ReadMe API v2)'
|
84
95
|
task publish: :environment do
|
85
96
|
Rake::Task["api_docs:generate"].invoke
|
86
97
|
Rake::Task["api_docs:upload"].invoke
|
87
|
-
|
98
|
+
|
99
|
+
# Check if rdme is available for uploading pages
|
100
|
+
if system("which rdme > /dev/null 2>&1")
|
101
|
+
puts "📄 Uploading documentation pages with rdme CLI..."
|
102
|
+
system("rdme docs upload #{ApiRegulator.configuration.docs_path}/")
|
103
|
+
else
|
104
|
+
puts "⚠️ rdme CLI not found. Skipping documentation pages upload."
|
105
|
+
puts " Install rdme CLI to upload documentation pages:"
|
106
|
+
puts " npm install -g rdme"
|
107
|
+
puts " rdme docs upload #{ApiRegulator.configuration.docs_path}/"
|
108
|
+
end
|
88
109
|
end
|
89
110
|
|
90
|
-
desc "Upload custom pages to ReadMe"
|
111
|
+
desc "Upload custom pages to ReadMe (DEPRECATED - Use rdme CLI instead)"
|
91
112
|
task :upload_pages => :environment do
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
#
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
request_body["slug"] ||= slug
|
116
|
-
|
117
|
-
raise("Title missing in #{file_path}") unless request_body["title"].present?
|
118
|
-
|
119
|
-
# Build the API request
|
120
|
-
if check_if_page_exists(slug)
|
121
|
-
uri = URI.parse("#{base_readme_api_endpoint}/#{slug}")
|
122
|
-
request = Net::HTTP::Put.new(uri)
|
123
|
-
else
|
124
|
-
uri = URI.parse("#{base_readme_api_endpoint}")
|
125
|
-
request = Net::HTTP::Post.new(uri)
|
126
|
-
end
|
127
|
-
request["Authorization"] = "Basic #{Base64.strict_encode64(readme_api_key)}"
|
128
|
-
request["Content-Type"] = "application/json"
|
129
|
-
request["x-readme-version"] = version if version.present?
|
130
|
-
request.body = request_body.compact.to_json
|
131
|
-
|
132
|
-
# Send the request
|
133
|
-
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
134
|
-
http.request(request)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Handle the response
|
138
|
-
case response.code.to_i
|
139
|
-
when 200
|
140
|
-
puts "Page '#{request_body["title"]}' successfully updated!"
|
141
|
-
when 201
|
142
|
-
puts "Page '#{request_body["title"]}' successfully created!"
|
143
|
-
else
|
144
|
-
puts "Failed to upload page '#{request_body["title"]}'!"
|
145
|
-
puts "Response Code: #{response.code}"
|
146
|
-
puts "Response Body: #{response.body}"
|
147
|
-
end
|
113
|
+
puts "⚠️ WARNING: This rake task is deprecated and may not work with ReadMe API v2."
|
114
|
+
puts " Please use the rdme CLI instead:"
|
115
|
+
puts " "
|
116
|
+
puts " # Install rdme CLI"
|
117
|
+
puts " npm install -g rdme"
|
118
|
+
puts " "
|
119
|
+
puts " # Authenticate with ReadMe"
|
120
|
+
puts " rdme login"
|
121
|
+
puts " "
|
122
|
+
puts " # Upload documentation pages"
|
123
|
+
puts " rdme docs upload #{ApiRegulator.configuration.docs_path}/"
|
124
|
+
puts " "
|
125
|
+
puts " For more information, see: https://github.com/readmeio/rdme"
|
126
|
+
puts " "
|
127
|
+
|
128
|
+
# Check if rdme is available
|
129
|
+
if system("which rdme > /dev/null 2>&1")
|
130
|
+
puts "✅ rdme CLI is installed. Running: rdme docs upload #{ApiRegulator.configuration.docs_path}/"
|
131
|
+
system("rdme docs upload #{ApiRegulator.configuration.docs_path}/")
|
132
|
+
else
|
133
|
+
puts "❌ rdme CLI not found. Please install it first:"
|
134
|
+
puts " npm install -g rdme"
|
135
|
+
exit 1
|
148
136
|
end
|
149
137
|
end
|
150
138
|
|
@@ -152,15 +140,13 @@ namespace :api_docs do
|
|
152
140
|
task :fetch_categories => :environment do
|
153
141
|
# Configuration
|
154
142
|
readme_api_key = ENV['RDME_API_KEY'].presence || raise("RDME_API_KEY is not set")
|
155
|
-
|
156
|
-
readme_categories_api_endpoint = "https://dash.readme.com/api/v1/categories"
|
143
|
+
readme_categories_api_endpoint = "https://api.readme.com/v2/categories"
|
157
144
|
|
158
145
|
# Build the API request
|
159
146
|
uri = URI.parse(readme_categories_api_endpoint)
|
160
147
|
request = Net::HTTP::Get.new(uri)
|
161
|
-
request["Authorization"] = "
|
148
|
+
request["Authorization"] = "Bearer #{readme_api_key}"
|
162
149
|
request["Content-Type"] = "application/json"
|
163
|
-
request["x-readme-version"] = version if version.present?
|
164
150
|
|
165
151
|
# Send the request
|
166
152
|
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
@@ -171,7 +157,10 @@ namespace :api_docs do
|
|
171
157
|
case response.code.to_i
|
172
158
|
when 200
|
173
159
|
puts "Categories"
|
174
|
-
|
160
|
+
response_data = JSON.parse(response.body)
|
161
|
+
# API v2 response format - returns data in a 'data' wrapper
|
162
|
+
categories = response_data.dig("data") || response_data
|
163
|
+
pp categories
|
175
164
|
else
|
176
165
|
puts "Failed to fetch categories"
|
177
166
|
puts "Response Code: #{response.code}"
|
@@ -195,14 +184,13 @@ namespace :api_docs do
|
|
195
184
|
[metadata, body]
|
196
185
|
end
|
197
186
|
|
198
|
-
def check_if_page_exists(slug)
|
187
|
+
def check_if_page_exists(slug, branch = "stable")
|
199
188
|
readme_api_key = ENV['RDME_API_KEY'].presence || raise("RDME_API_KEY is not set")
|
200
|
-
|
201
|
-
uri = URI.parse("https://
|
189
|
+
|
190
|
+
uri = URI.parse("https://api.readme.com/v2/custom_pages/#{slug}")
|
202
191
|
request = Net::HTTP::Get.new(uri)
|
203
|
-
request["Authorization"] = "
|
192
|
+
request["Authorization"] = "Bearer #{readme_api_key}"
|
204
193
|
request["Content-Type"] = "application/json"
|
205
|
-
request["x-readme-version"] = version if version.present?
|
206
194
|
|
207
195
|
# Send the request
|
208
196
|
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api-regulator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geoff Massanek
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|