api-regulator 0.1.27 → 0.1.28

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1930002f6e2b1b916f44c2aaf447b624c373f5393297d7aa12b665063ec75a56
4
- data.tar.gz: f98dc9238b359bf019eeffe6f0f5a3a0dc001f8f8af91d80ba042828621cd699
3
+ metadata.gz: a4adbf41faf31da6c2dfd0ac4fa34753b1b145e4a54fe150716b248c0bb2ca8f
4
+ data.tar.gz: 3bf906b1cc68f8729c8593fda4af679525999b6d4ed27f8036b96a9b4a90466a
5
5
  SHA512:
6
- metadata.gz: effb1e8e1cac07f20aa41dd4398b146afa13a59769c687bfc740730ae3a9bf7a84d81805dc11e0a0073c97c3375689d6d78647bef7cc1543ede8c065c1956474
7
- data.tar.gz: a951dc617505560736c62a34aa4eae3d2c99364a39953ee64d337c232b516f9949d1cf90de9859d9d9b33c2036f42fc9421ea7ceabdf5ae81099b4f4bc9b8675
6
+ metadata.gz: 92cf6b80afec1af5113edb3ac6dfd64211931a3c47ade5b5aad032ed6c35343357cc158eebe7e5a27fb4a65ca600584bb64cbfaf36eb6532ebd721c98588157d
7
+ data.tar.gz: 1a5e008679121223946897c93b2a89efd1be92c267b4b5ffb07e484c35938236f842ba1fd2e9eea9c5de60bc1a5e931a95f207e348abe4062fde7a4f2d6a1227
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- api-regulator (0.1.27)
4
+ api-regulator (0.1.28)
5
5
  activemodel (~> 8.0)
6
6
  activesupport (~> 8.0)
7
7
 
data/README.md CHANGED
@@ -1,25 +1,21 @@
1
1
  # ApiRegulator
2
2
 
3
- ApiRegulator is a Ruby gem designed to **document** and **validate APIs** in Rails applications. It provides a clean DSL for defining API endpoints, parameter validations, and response schemas directly in your Rails controllers, while also generating OpenAPI 3.1.0-compliant documentation for tools like Swagger and ReadMe.
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 relies on **Active Model validations** for parameter validation, making it familiar and intuitive for Rails developers.
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
- - **API Documentation DSL**:
10
- Define API endpoints, request parameters, and response schemas in an intuitive, Rails-friendly DSL.
11
-
12
- - **Dynamic Validation**:
13
- Automatically validate incoming requests against the defined parameters using **Active Model validations**, reducing boilerplate code.
14
-
15
- - **OpenAPI Documentation**:
16
- Generate fully compliant OpenAPI 3.1.0 JSON files, ready for use with documentation tools like Swagger or ReadMe.
17
-
18
- - **Reusability**:
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 uploading documentation 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,523 @@ gem 'api_regulator'
31
27
 
32
28
  Run `bundle install` to install the gem.
33
29
 
34
-
35
30
  ## Setup
36
31
 
37
- 1. **Create an Initializer**:
38
-
39
- Add the following to `config/initializers/api_regulator.rb`:
32
+ ### 1. Create an Initializer
40
33
 
41
- ```ruby
42
- ApiRegulator.configure do |config|
43
- config.api_base_url = "/api/v1" # Set a common base path for your API endpoints
44
- config.docs_path = Rails.root.join("doc").to_s # Path for folder for docs
45
- config.app_name = "My API" # shows in docs
34
+ Add the following to `config/initializers/api_regulator.rb`:
46
35
 
47
- # Optional: ReadMe versions and API ID for schema uploads
48
- config.versions = {
49
- "v1.0" => "abc123",
50
- "v1.0-internal" => "abc345"
51
- }
52
- config.default_version = "v1.0-internal"
36
+ ```ruby
37
+ ApiRegulator.configure do |config|
38
+ config.api_base_url = "/api/v1"
39
+ config.docs_path = Rails.root.join("doc").to_s
40
+ config.app_name = "My API"
41
+
42
+ # Optional: Configure multiple API versions
43
+ config.versions = {
44
+ "v1.0" => "abc123", # ReadMe API spec ID
45
+ "v1.0-internal" => "abc345" # Internal version
46
+ }
47
+ config.default_version = "v1.0-internal"
48
+
49
+ # Optional: Define API servers
50
+ config.servers = [
51
+ { url: "https://stg.example.com", description: "Staging", "x-default": true },
52
+ { url: "https://example.com", description: "Production" }
53
+ ]
54
+ end
55
+ ```
53
56
 
54
- config.servers = [
55
- { url: "https://stg.example.com", description: "Staging", "x-default": true },
56
- { url: "https://example.com", description: "Production" }
57
- ]
58
- end
59
- ```
57
+ ### 2. Include the DSL in Your Base Controller
60
58
 
61
- 2. **Include the DSL in Your Base Controller**:
59
+ ```ruby
60
+ class Api::ApplicationController < ActionController::API
61
+ include ApiRegulator::DSL
62
+ include ApiRegulator::ControllerMixin
63
+ end
64
+ ```
62
65
 
63
- Include the DSL and validation methods in your base API controller:
66
+ ### 3. Define Security Schemes (Optional)
64
67
 
65
- ```ruby
66
- class Api::ApplicationController < ActionController::API
67
- include ApiRegulator::DSL
68
- include ApiRegulator::ControllerMixin
69
- end
70
- ```
68
+ ```ruby
69
+ # In your initializer
70
+ ApiRegulator.security_schemes = {
71
+ bearer_auth: {
72
+ type: "http",
73
+ scheme: "bearer",
74
+ bearerFormat: "JWT"
75
+ },
76
+ api_key: {
77
+ type: "apiKey",
78
+ in: "header",
79
+ name: "X-API-Key"
80
+ }
81
+ }
82
+ ```
71
83
 
72
84
  ## Usage
73
85
 
74
- **Defining Endpoints**
75
-
76
- Use the DSL in your controllers to define API endpoints, request parameters, and response schemas.
86
+ ### Basic API Definition
77
87
 
78
88
  ```ruby
79
89
  class Api::V1::CustomersController < Api::ApplicationController
80
- api self, :create, "Enroll a customer" do
90
+ api self, :create, desc: "Create a new customer", title: "Create Customer" do
91
+ # Path parameters
92
+ param :organization_id, :string, location: :path, presence: true
93
+
94
+ # Query parameters
95
+ param :expand, :string, location: :query, desc: "Comma-separated list of fields to expand"
96
+
97
+ # Body parameters
81
98
  param :customer, presence: true do
82
99
  param :first_name, :string, presence: true
83
100
  param :last_name, :string, presence: true
84
- param :email, :string, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
85
- param :ssn, :string, presence: true, length: { minimum: 9, maximum: 9 }
101
+ param :email, :string, presence: true, format: { with: ApiRegulator::Formats::EMAIL }
102
+ param :ssn, :string, presence: true, length: { is: 9 }
103
+ param :date_of_birth, :string, format: { with: ApiRegulator::Formats::DATE }
104
+
105
+ # Nested objects
106
+ param :address, :object do
107
+ param :street, :string, presence: true
108
+ param :city, :string, presence: true
109
+ param :state, :string, presence: true, length: { is: 2 }
110
+ param :zip_code, :string, format: { with: ApiRegulator::Formats::ZIP_CODE }
111
+ end
112
+
113
+ # Arrays
114
+ param :phone_numbers, :array, item_type: :string
115
+ param :emergency_contacts, :array do
116
+ param :name, :string, presence: true
117
+ param :relationship, :string, presence: true
118
+ param :phone, :string, presence: true
119
+ end
86
120
  end
87
121
 
88
- response 200, "Customer successfully enrolled" do
122
+ # Response definitions
123
+ response 201, "Customer successfully created" do
89
124
  param :customer do
90
- param :id, :string, desc: "Customer ID"
91
- param :email, :string, desc: "Customer email"
125
+ param :id, :string, desc: "Customer UUID"
126
+ param :email, :string, desc: "Customer email address"
127
+ param :created_at, :string, desc: "ISO 8601 timestamp"
92
128
  end
93
129
  end
94
130
 
95
131
  response 422, ref: :validation_errors
132
+ response 401, ref: :unauthorized_error
96
133
  end
97
134
 
98
135
  def create
99
- validate_params! # Validate request params against the DSL definition
100
-
101
- customer = Customer.create!(api_params[:customer]) # Use dynamically generated params
102
- render json: customer, status: :ok
136
+ validate_params! # Validates against DSL definition
137
+
138
+ customer = Customer.create!(api_params[:customer])
139
+ render json: { customer: customer }, status: :created
103
140
  end
104
141
  end
105
142
  ```
106
143
 
107
- ## Shared Schemas
144
+ ### Advanced Parameter Options
145
+
146
+ #### Conditional Requirements
147
+
148
+ ```ruby
149
+ param :ssn, :string, presence: {
150
+ required_on: [:create, :update], # Required only for these actions
151
+ required_except_on: [:show] # Required except for these actions
152
+ }
153
+ ```
108
154
 
109
- Define reusable schemas for common responses in your initializer:
155
+ #### Version-Specific Parameters
110
156
 
111
157
  ```ruby
158
+ param :legacy_field, :string, versions: [:v1], desc: "Only available in v1"
159
+ param :new_feature, :boolean, versions: [:v2, :v3], desc: "Available in v2 and v3"
160
+ ```
161
+
162
+ #### Type Validation and Formatting
163
+
164
+ ```ruby
165
+ param :age, :integer, numericality: { greater_than: 0, less_than: 150 }
166
+ param :website, :string, format: { with: ApiRegulator::Formats::URI }
167
+ param :score, :number, numericality: { greater_than_or_equal_to: 0.0, less_than_or_equal_to: 100.0 }
168
+ param :is_active, :boolean
169
+ param :tags, :array, item_type: :string, inclusion: { in: ["vip", "standard", "premium"] }
170
+ ```
171
+
172
+ #### Arbitrary Keys Support
173
+
174
+ ```ruby
175
+ param :metadata, :object, allow_arbitrary_keys: true do
176
+ param :created_by, :string # Known fields can still be defined
177
+ end
178
+ ```
179
+
180
+ #### Nullable Fields
181
+
182
+ ```ruby
183
+ param :middle_name, :string, presence: { allow_nil: true }
184
+ param :optional_date, :string, format: { with: ApiRegulator::Formats::DATE, allow_nil: true }
185
+ ```
186
+
187
+ ### Shared Schemas
188
+
189
+ Define reusable schemas in your initializer:
190
+
191
+ ```ruby
192
+ # Common error responses
112
193
  ApiRegulator.register_shared_schema :validation_errors, "Validation error response" do
113
- param :errors, :array, desc: "Array of validation errors", items_type: :string
194
+ param :errors, :array, desc: "Array of validation error messages" do
195
+ param :field, :string, desc: "Field name that failed validation"
196
+ param :message, :string, desc: "Human-readable error message"
197
+ param :code, :string, desc: "Error code for programmatic handling"
198
+ end
199
+ end
200
+
201
+ ApiRegulator.register_shared_schema :unauthorized_error, "Authentication required" do
202
+ param :error, :string, desc: "Error message"
203
+ param :code, :integer, desc: "HTTP status code"
204
+ end
205
+
206
+ # Common response objects
207
+ ApiRegulator.register_shared_schema :pagination_meta, "Pagination metadata" do
208
+ param :current_page, :integer, desc: "Current page number"
209
+ param :per_page, :integer, desc: "Items per page"
210
+ param :total_pages, :integer, desc: "Total number of pages"
211
+ param :total_count, :integer, desc: "Total number of items"
114
212
  end
115
213
  ```
116
214
 
117
- Reference the shared schema in your responses:
215
+ Use shared schemas in your API definitions:
216
+
118
217
  ```ruby
119
- response 422, ref: :validation_errors
218
+ api self, :index do
219
+ param :page, :integer, location: :query, desc: "Page number"
220
+ param :per_page, :integer, location: :query, desc: "Items per page"
221
+
222
+ response 200, "List of customers" do
223
+ param :customers, :array do
224
+ ref :customer_summary # Reference another shared schema
225
+ end
226
+ ref :pagination_meta
227
+ end
120
228
  end
121
229
  ```
122
230
 
123
- ## Generating OpenAPI Documentation
231
+ ### Webhook Documentation
124
232
 
125
- Generate OpenAPI documentation using the provided Rake tasks:
233
+ Define webhook payloads using the same DSL:
234
+
235
+ ```ruby
236
+ class WebhookDefinitions < Api::ApplicationController
237
+ webhook :customer_created,
238
+ desc: "Fired when a new customer is created",
239
+ title: "Customer Created",
240
+ tags: ["customers", "webhooks"] do
241
+
242
+ param :event, :string, desc: "Event name"
243
+ param :timestamp, :string, desc: "ISO 8601 timestamp"
244
+ param :data do
245
+ param :customer do
246
+ param :id, :string, desc: "Customer UUID"
247
+ param :email, :string, desc: "Customer email"
248
+ param :created_at, :string, desc: "ISO 8601 timestamp"
249
+ end
250
+ end
251
+
252
+ example :basic_example, {
253
+ event: "customer.created",
254
+ timestamp: "2024-01-15T10:30:00Z",
255
+ data: {
256
+ customer: {
257
+ id: "cust_abc123",
258
+ email: "john@example.com",
259
+ created_at: "2024-01-15T10:30:00Z"
260
+ }
261
+ }
262
+ }, default: true
263
+ end
264
+ end
265
+ ```
126
266
 
267
+ ### API Examples
127
268
 
128
- 1. **Generate the Schema:**
129
- ```bash
130
- rake api_docs:generate # uses default (or no) version
131
- VERSION=v1.0-internal rake api_docs:generate # specifies the to generate
132
- ```
269
+ Add examples to your API definitions:
133
270
 
134
- 2. **Upload to ReadMe (Optional)**:
135
- ```bash
136
- rake api_docs:upload
137
- ```
138
- This uploads the OpenAPI file to ReadMe. Ensure you’ve configured the RDME_API_KEY and optional RDME_API_ID.
271
+ ```ruby
272
+ api self, :create do
273
+ param :customer do
274
+ param :name, :string, presence: true
275
+ param :email, :string, presence: true
276
+ end
277
+
278
+ example :successful_creation, {
279
+ customer: {
280
+ name: "John Doe",
281
+ email: "john@example.com"
282
+ }
283
+ }, default: true
284
+
285
+ example :with_optional_fields, {
286
+ customer: {
287
+ name: "Jane Smith",
288
+ email: "jane@example.com",
289
+ phone: "+1-555-0123"
290
+ }
291
+ }
292
+ end
293
+ ```
294
+
295
+ ## Validation and Error Handling
296
+
297
+ ### Automatic Parameter Validation
298
+
299
+ ```ruby
300
+ def create
301
+ validate_params! # Raises ApiRegulator::InvalidParams or ApiRegulator::UnexpectedParams
302
+
303
+ # Access validated and type-converted parameters
304
+ customer_data = api_params[:customer]
305
+ # Process with confidence that data is valid
306
+ end
307
+ ```
308
+
309
+ ### Custom Error Handling
310
+
311
+ ```ruby
312
+ class Api::ApplicationController < ActionController::API
313
+ include ApiRegulator::DSL
314
+ include ApiRegulator::ControllerMixin
315
+
316
+ rescue_from ApiRegulator::InvalidParams do |exception|
317
+ render json: {
318
+ errors: exception.errors.messages,
319
+ message: "Validation failed"
320
+ }, status: :unprocessable_entity
321
+ end
322
+
323
+ rescue_from ApiRegulator::UnexpectedParams do |exception|
324
+ render json: {
325
+ errors: exception.details,
326
+ message: "Unexpected parameters provided"
327
+ }, status: :bad_request
328
+ end
329
+ end
330
+ ```
139
331
 
140
- 3. **Publish Both**:
141
- ```bash
142
- rake api_docs:publish
143
- ```
332
+ ## OpenAPI Documentation Generation
144
333
 
145
- ## Contributing
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.
334
+ ### Generate Documentation
151
335
 
152
- ## Releasing a new version
153
- `api-regulator` is published to [rubygems](https://rubygems.org/gems/api-regulator). To release a new version,
154
- 1. In your PR, bump the version in `lib/api_regulator/version.rb`
155
- 2. Run `bundle install` (this should update your `Gemfile.lock`)
156
- 3. Go through code review and merge your PR
157
- 4. Trigger the [`Release Gem`](https://github.com/Stellarcred/api-regulator/actions/workflows/release.yml) workflow from the main branch.
158
- 5. Verify your new version is available in [rubygems](https://rubygems.org/gems/api-regulator).
336
+ ```bash
337
+ # Generate for default version
338
+ rake api_docs:generate
339
+
340
+ # Generate for specific version
341
+ VERSION=v1.0 rake api_docs:generate
342
+
343
+ # Generate for all configured versions
344
+ rake api_docs:generate_all
345
+ ```
346
+
347
+ ### Upload to ReadMe
348
+
349
+ Set up your ReadMe credentials:
350
+
351
+ ```bash
352
+ export RDME_API_KEY="your_readme_api_key"
353
+ ```
354
+
355
+ ```bash
356
+ # Upload API specification
357
+ rake api_docs:upload
358
+
359
+ # Upload custom documentation pages (with YAML frontmatter)
360
+ rake api_docs:upload_pages
361
+
362
+ # Generate and upload everything
363
+ rake api_docs:publish
364
+ ```
365
+
366
+ ### Custom Documentation Pages
367
+
368
+ Create markdown files in your `docs_path` with YAML frontmatter:
369
+
370
+ ```markdown
371
+ ---
372
+ title: "Getting Started"
373
+ slug: "getting-started"
374
+ category: "documentation"
375
+ hidden: false
376
+ ---
377
+
378
+ # Getting Started
379
+
380
+ Your API documentation content here...
381
+ ```
382
+
383
+ ### ReadMe Integration Features
384
+
385
+ ```bash
386
+ # Fetch available categories
387
+ rake api_docs:fetch_categories
388
+
389
+ # Upload with specific version
390
+ VERSION=v2.0 rake api_docs:upload
391
+ ```
392
+
393
+ ## Built-in Format Validators
394
+
395
+ ApiRegulator includes common format validators:
396
+
397
+ ```ruby
398
+ ApiRegulator::Formats::DATE # ISO 8601 date format
399
+ ApiRegulator::Formats::DATETIME # ISO 8601 datetime format
400
+ ApiRegulator::Formats::EMAIL # Email address validation
401
+ ApiRegulator::Formats::ZIP_CODE # US ZIP code (12345 or 12345-6789)
402
+ ApiRegulator::Formats::URI # URI format validation
403
+ ```
404
+
405
+ Usage example:
406
+
407
+ ```ruby
408
+ param :email, :string, format: { with: ApiRegulator::Formats::EMAIL }
409
+ param :website, :string, format: { with: ApiRegulator::Formats::URI }
410
+ param :birth_date, :string, format: { with: ApiRegulator::Formats::DATE }
411
+ ```
412
+
413
+ ## Testing Your APIs
414
+
415
+ ApiRegulator integrates seamlessly with RSpec:
416
+
417
+ ```ruby
418
+ RSpec.describe Api::V1::CustomersController do
419
+ describe "POST /api/v1/customers" do
420
+ it "validates required parameters" do
421
+ post "/api/v1/customers", params: {}
422
+ expect(response).to have_http_status(:unprocessable_entity)
423
+ end
424
+
425
+ it "creates customer with valid parameters" do
426
+ params = {
427
+ customer: {
428
+ first_name: "John",
429
+ last_name: "Doe",
430
+ email: "john@example.com"
431
+ }
432
+ }
433
+
434
+ post "/api/v1/customers", params: params
435
+ expect(response).to have_http_status(:created)
436
+ end
437
+ end
438
+ end
439
+ ```
440
+
441
+ ## Configuration Reference
442
+
443
+ ```ruby
444
+ ApiRegulator.configure do |config|
445
+ # Base URL for all API endpoints (default: "api/v1")
446
+ config.api_base_url = "/api/v1"
447
+
448
+ # Application name shown in documentation (default: "API Documentation")
449
+ config.app_name = "My API"
450
+
451
+ # Directory for documentation files (default: "doc")
452
+ config.docs_path = Rails.root.join("doc").to_s
453
+
454
+ # Version mapping for ReadMe (optional)
455
+ config.versions = {
456
+ "v1.0" => "readme_spec_id_1",
457
+ "v2.0" => "readme_spec_id_2"
458
+ }
459
+
460
+ # Default version when none specified (optional)
461
+ config.default_version = "v1.0"
462
+
463
+ # Server definitions for OpenAPI spec (optional)
464
+ config.servers = [
465
+ { url: "https://api.example.com", description: "Production" },
466
+ { url: "https://staging-api.example.com", description: "Staging" }
467
+ ]
468
+ end
469
+ ```
470
+
471
+ ## Advanced Usage
472
+
473
+ ### Multiple API Versions
474
+
475
+ ```ruby
476
+ # Define version-specific endpoints
477
+ api self, :create, versions: [:v1, :v2] do
478
+ param :name, :string, presence: true
479
+ param :email, :string, presence: true, versions: [:v1, :v2]
480
+ param :phone, :string, versions: [:v2] # Only in v2
481
+ end
482
+ ```
483
+
484
+ ### Security Requirements
485
+
486
+ ```ruby
487
+ api self, :create do
488
+ # This endpoint requires authentication
489
+ security [{ bearer_auth: [] }]
490
+
491
+ param :customer do
492
+ param :name, :string, presence: true
493
+ end
494
+ end
495
+ ```
496
+
497
+ ### Custom Validation Context
498
+
499
+ ```ruby
500
+ def update
501
+ # Validate with specific context
502
+ validate_params!
503
+
504
+ # The validation context is automatically set to the action name (:update)
505
+ # This allows conditional validations based on the action
506
+ end
507
+ ```
508
+
509
+ ## Error Reference
510
+
511
+ - `ApiRegulator::InvalidParams`: Raised when request parameters fail validation
512
+ - `ApiRegulator::UnexpectedParams`: Raised when unexpected parameters are provided
513
+ - `ApiRegulator::ValidationError`: Base class for validation errors
514
+
515
+ ## Development and Contributing
516
+
517
+ 1. Fork the repository
518
+ 2. Create your feature branch (`git checkout -b feature/new-feature`)
519
+ 3. Write tests for your changes
520
+ 4. Ensure all tests pass (`bundle exec rspec`)
521
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
522
+ 6. Push to the branch (`git push origin feature/new-feature`)
523
+ 7. Open a pull request
524
+
525
+ ### Running Tests
526
+
527
+ ```bash
528
+ bundle install
529
+ bundle exec rspec
530
+ ```
531
+
532
+ ## Releasing New Versions
533
+
534
+ ApiRegulator is published to [RubyGems](https://rubygems.org/gems/api-regulator). To release:
535
+
536
+ 1. Update version in `lib/api_regulator/version.rb`
537
+ 2. Run `bundle install` to update `Gemfile.lock`
538
+ 3. Create PR and merge after review
539
+ 4. Trigger the [Release Gem workflow](https://github.com/Stellarcred/api-regulator/actions/workflows/release.yml)
540
+ 5. Verify publication on [RubyGems](https://rubygems.org/gems/api-regulator)
541
+
542
+ ## Requirements
543
+
544
+ - Ruby >= 3.0
545
+ - Rails >= 8.0 (ActiveSupport and ActiveModel)
159
546
 
160
547
  ## License
548
+
161
549
  This gem is available as open-source software under the [MIT License](https://mit-license.org/).
@@ -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 tags
92
+ def default_tags
92
93
  [
93
94
  controller_name
94
95
  .demodulize
@@ -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
 
@@ -1,3 +1,3 @@
1
1
  module ApiRegulator
2
- VERSION = "0.1.27"
2
+ VERSION = "0.1.28"
3
3
  end
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.1.27
4
+ version: 0.1.28
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-04-17 00:00:00.000000000 Z
11
+ date: 2025-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport