openapi_blocks 0.4.1 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eafa1f0685d4c659609b5116dfac6e7204cee4bd5c60ea882417aebbe4cd67dd
4
- data.tar.gz: db613ff23df3f705b70f126f02a0d03334fffe8a8fcbfd3dbe563343fce69ef8
3
+ metadata.gz: a555c50cffdc3d57e766d1d644a2a7715ac4ab3ad730484169f86b09538d9da9
4
+ data.tar.gz: e55fe98e2c802e9823bef23683a8b431e97ecda4d7f6781d02995a7f5d9d1da7
5
5
  SHA512:
6
- metadata.gz: f88f54dcc99be63820da03cedaa9062d5e1c3e185c1cbf0d6aa3ac2c00f066b9ea75002dd1e8d4061f51c0f4bb71d606dc5b632de4f80870f3c598bd47312ef7
7
- data.tar.gz: 75027794cbdebde235211302cc5da8495f2dba128441cdd8d94bfea4d7808acd1a66ef40569f768698c5c2b32fba205f99c71305673105b0229276d4c9c9e505
6
+ metadata.gz: 223d4851ce536c0d9cc685e5098bfe6bb3dbb9cd278ecf7f28287eab0aa6ed58fc06ecad9b1ee470f55a10843256c4e89f6c1ce298d5effadc3140597cdc375a
7
+ data.tar.gz: 65d27cbd44d7f8555d9fe9ad6fdf147f25e0d7e888411ba3aeef7db80ff085799d8c25d4a4dfebbfd33f0285bb3695c00af12c793609b3018f893b233e4f164d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0] - 2026-06-02
11
+
12
+ - Added generators
13
+
10
14
  ## [0.4.1] - 2026-06-02
11
15
 
12
16
  - Change parallel version
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # OpenapiBlocks
2
2
 
3
- OpenapiBlocks is a Rails gem that automatically generates OpenAPI 3.0/3.1 documentation from your ActiveRecord models, ActiveModel validations, and Rails routes — inspired by [ActiveModel::Serializer](https://github.com/rails-api/active_model_serializers).
3
+ OpenapiBlocks is a Rails gem that automatically generates OpenAPI 3.0/3.1 documentation from your ActiveRecord models, ActiveModel validations, and Rails routes — inspired by ActiveModel::Serializer (https://github.com/rails-api/active_model_serializers).
4
4
 
5
- Versão em português brasileiro: [README.pt-BR.md](README.pt-BR.md)
5
+ Versão em português brasileiro: README.pt-BR.md
6
6
 
7
- No manual annotation. No DSL noise in your controllers. Just declare what to expose and the spec is generated automatically. Includes a high-performance built-in serializer — ~3.6× faster than `as_json` with consistent linear scaling from 10 to 5000 records.
7
+ No manual annotation. No DSL noise in your controllers. Just declare what to expose and the spec is generated automatically. Includes a high-performance built-in serializer — ~3.6× faster than as_json with consistent linear scaling from 10 to 5000 records.
8
8
 
9
9
  ---
10
10
 
11
11
  ## Installation
12
12
 
13
- Add to your `Gemfile`:
13
+ Add to your Gemfile:
14
14
 
15
15
  ```ruby
16
16
  gem "openapi_blocks"
@@ -24,6 +24,70 @@ bundle install
24
24
 
25
25
  ---
26
26
 
27
+ ## Generators
28
+
29
+ OpenapiBlocks provides three generators to get you started quickly.
30
+
31
+ ### Install
32
+
33
+ ```bash
34
+ rails generate openapi_blocks:install
35
+ ```
36
+
37
+ Creates `config/initializers/openapi_blocks.rb` with all available options commented out, and mounts the engine in `config/routes.rb`:
38
+
39
+ ```ruby
40
+ mount OpenapiBlocks::Engine => "/docs"
41
+ ```
42
+
43
+ ### Openapi
44
+
45
+ ```bash
46
+ rails generate openapi_blocks:openapi User
47
+ ```
48
+
49
+ Creates `app/openapi/user_openapi.rb` with all available DSL options commented out:
50
+
51
+ ```ruby
52
+ # app/openapi/user_openapi.rb
53
+ class UserOpenapi < OpenapiBlocks::Controller
54
+ # resource UserSerializer
55
+ # controller UsersController
56
+
57
+ # tags "Users"
58
+
59
+ # operation :index do
60
+ # summary "List all users"
61
+ # response 200, description: "List of users", schema: { type: :array, items: :User }
62
+ # end
63
+ end
64
+ ```
65
+
66
+ ### Serializer
67
+
68
+ ```bash
69
+ rails generate openapi_blocks:serializer User
70
+ ```
71
+
72
+ Creates `app/serializers/user_serializer.rb` with all available DSL options commented out:
73
+
74
+ ```ruby
75
+ # app/serializers/user_serializer.rb
76
+ class UserSerializer < OpenapiBlocks::Serializer
77
+ # ignore :password_digest, :reset_password_token
78
+
79
+ # association :posts, type: :array, read_only: true
80
+ # association :company
81
+
82
+ # attribute :full_name, type: :string, read_only: true
83
+ # def full_name
84
+ # "#{object.first_name} #{object.last_name}"
85
+ # end
86
+ end
87
+ ```
88
+
89
+ ---
90
+
27
91
  ## Setup
28
92
 
29
93
  ### 1. Mount the Engine
@@ -48,7 +112,7 @@ GET /docs/openapi.yaml -> OpenAPI spec in YAML
48
112
 
49
113
  ### 2. Configure the initializer
50
114
 
51
- `OpenapiBlocks.configure` is required. The gem raises `OpenapiBlocks::Error` on the first request if it was never called or if `info.title` / `info.version` are blank.
115
+ OpenapiBlocks.configure is required. The gem raises OpenapiBlocks::Error on the first request if it was never called or if info.title / info.version are blank.
52
116
 
53
117
  ```ruby
54
118
  # config/initializers/openapi_blocks.rb
@@ -101,9 +165,9 @@ end
101
165
 
102
166
  OpenapiBlocks provides two base classes with distinct responsibilities:
103
167
 
104
- - `OpenapiBlocks::Serializer` — defines the model, fields, associations, and serialization logic. Lives in `app/serializers/`.
105
- - `OpenapiBlocks::Controller` — defines API operations, parameters, and responses for documentation. Lives in `app/openapi/`.
106
- - `OpenapiBlocks::Base` — legacy base class that combines both concerns. Still supported.
168
+ - OpenapiBlocks::Serializer — defines the model, fields, associations, and serialization logic. Lives in app/serializers/.
169
+ - OpenapiBlocks::Controller — defines API operations, parameters, and responses for documentation. Lives in app/openapi/.
170
+ - OpenapiBlocks::Base — legacy base class that combines both concerns. Still supported.
107
171
 
108
172
  ### Recommended: Serializer + Controller
109
173
 
@@ -142,7 +206,7 @@ end
142
206
  ```ruby
143
207
  # app/openapi/user_openapi.rb
144
208
  class UserOpenapi < OpenapiBlocks::Controller
145
- resource UserSerializer
209
+ resource UserSerializer # links to the serializer — schema is derived from it
146
210
  controller UsersController
147
211
 
148
212
  tags "Users"
@@ -169,6 +233,19 @@ class UserOpenapi < OpenapiBlocks::Controller
169
233
  end
170
234
  ```
171
235
 
236
+ #### How the OpenAPI schema is generated
237
+
238
+ When `resource UserSerializer` is declared in a `Controller`, OpenapiBlocks derives the OpenAPI schema directly from the serializer — not from the model. This guarantees that what is documented is exactly what the API returns.
239
+
240
+ The schema is built from three sources on the serializer:
241
+
242
+ - ActiveRecord columns — read from `db/schema.rb` via the inferred model. Column types are mapped to OpenAPI types automatically.
243
+ - `attribute` declarations — virtual fields not present in the database. Fields declared with `read_only: true` appear in the `User` response schema but are excluded from the `UserInput` request schema.
244
+ - `association` declarations — resolved as `$ref` to the associated schema. Associations declared with `read_only: true` appear in the response but are excluded from `UserInput`.
245
+ - `ignore` declarations — columns excluded from both schemas.
246
+
247
+ The `UserInput` schema (used in POST, PUT and PATCH request bodies) is derived automatically from the `User` schema by removing `id`, `created_at`, `updated_at`, and any field marked `read_only: true`.
248
+
172
249
  ```ruby
173
250
  # app/controllers/users_controller.rb
174
251
  def index
@@ -229,7 +306,7 @@ def show
229
306
  end
230
307
  ```
231
308
 
232
- Serializer registration is automatic by convention (`UserSerializer` -> `User`). For explicit registration:
309
+ Serializer registration is automatic by convention (UserSerializer -> User). For explicit registration:
233
310
 
234
311
  ```ruby
235
312
  class AdminUserSerializer < OpenapiBlocks::Serializer
@@ -243,34 +320,34 @@ If no serializer is found, OpenapiBlocks falls back to default Rails rendering a
243
320
 
244
321
  ## Serializer
245
322
 
246
- The built-in serializer compiles a monolithic extractor method per class at boot time using `class_eval`. There are no loops, no lambda indirection, and no runtime branching per object.
323
+ The built-in serializer compiles a monolithic extractor method per class at boot time using class_eval. There are no loops, no lambda indirection, and no runtime branching per object.
247
324
 
248
325
  ### Performance (200 records, arm64, Ruby 4.0)
249
326
 
250
- | Method | i/s | μs/i | vs serialize |
327
+ | Method | i/s | us/i | vs serialize |
251
328
  | ---------- | ----- | ---- | ------------ |
252
329
  | serialize | 4 239 | 235 | — |
253
- | to_json | 1 444 | 692 | 2.94× slower |
254
- | as_json | 1 186 | 843 | 3.58× slower |
255
- | oj+as_json | 1 126 | 888 | 3.77× slower |
330
+ | to_json | 1 444 | 692 | 2.94x slower |
331
+ | as_json | 1 186 | 843 | 3.58x slower |
332
+ | oj+as_json | 1 126 | 888 | 3.77x slower |
256
333
 
257
- Scaling is linear — the 3. advantage over `as_json` holds from 10 to 5000 records.
334
+ Scaling is linear — the 3.6x advantage over as_json holds from 10 to 5000 records.
258
335
 
259
336
  ### Virtual attributes and method resolution
260
337
 
261
- | Declared with | Method in serializer? | Calls |
262
- | ---------------------- | --------------------- | --------------------------------------- |
263
- | `attribute :full_name` | yes | `serializer_instance.full_name` |
264
- | `attribute :full_name` | no | `object.full_name` (delegated to model) |
265
- | column in db | — | `object.attribute` (direct) |
338
+ | Declared with | Method in serializer? | Calls |
339
+ | -------------------- | --------------------- | ------------------------------------- |
340
+ | attribute :full_name | yes | serializer_instance.full_name |
341
+ | attribute :full_name | no | object.full_name (delegated to model) |
342
+ | column in db | — | object.attribute (direct) |
266
343
 
267
344
  ### Association serializer resolution
268
345
 
269
346
  For each association, the serializer resolves the serializer class in this order:
270
347
 
271
- 1. `PostSerializer` — has `serialize`, used directly.
272
- 2. `PostOpenapi` — is a `Controller`, delegates to its `resource`.
273
- 3. Fallback — calls `as_json` on the association value.
348
+ 1. PostSerializer — has serialize, used directly.
349
+ 2. PostOpenapi — is a Controller, delegates to its resource.
350
+ 3. Fallback — calls as_json on the association value.
274
351
 
275
352
  ---
276
353
 
@@ -289,14 +366,14 @@ end
289
366
 
290
367
  OpenapiBlocks generates:
291
368
 
292
- - `User` schema from `db/schema.rb` columns and types
293
- - `UserInput` schema for `POST`, `PUT` and `PATCH` request bodies (without `id`, `created_at`, `updated_at` and `read_only` fields)
294
- - `required` fields from `presence: true` validations
295
- - `minLength`, `maxLength` from `length` validations
296
- - `minimum`, `maximum` from `numericality` validations
297
- - `enum` from `inclusion` validations
298
- - `format: "email"` from format validations
299
- - All paths from `config/routes.rb`
369
+ - User schema from db/schema.rb columns and types
370
+ - UserInput schema for POST, PUT and PATCH request bodies (without id, created_at, updated_at and read_only fields)
371
+ - required fields from presence: true validations
372
+ - minLength, maxLength from length validations
373
+ - minimum, maximum from numericality validations
374
+ - enum from inclusion validations
375
+ - format: "email" from format validations
376
+ - All paths from config/routes.rb
300
377
 
301
378
  ---
302
379
 
@@ -339,10 +416,10 @@ association :posts, type: :array, read_only: true # excluded from UserInput (re
339
416
 
340
417
  Virtual attributes are fields that exist in the API response but not in the database.
341
418
 
342
- | Option | Description | Appears in User | Appears in UserInput |
343
- | ------------------ | -------------------------------------- | :-------------: | :------------------: |
344
- | `read_only: true` | Calculated or system-generated fields | YES | NO |
345
- | `read_only: false` | Fields the client can send and receive | YES | YES |
419
+ | Option | Description | Appears in User | Appears in UserInput |
420
+ | ---------------- | -------------------------------------- | :-------------: | :------------------: |
421
+ | read_only: true | Calculated or system-generated fields | YES | NO |
422
+ | read_only: false | Fields the client can send and receive | YES | YES |
346
423
 
347
424
  ```ruby
348
425
  attribute :full_name, type: :string, read_only: true # response only
@@ -354,19 +431,19 @@ attribute :nickname, type: :string # request and response
354
431
 
355
432
  ## Type Mapping
356
433
 
357
- | ActiveRecord type | OpenAPI type |
358
- | ----------------- | ---------------------- |
359
- | `integer` | `integer` / `int32` |
360
- | `bigint` | `integer` / `int64` |
361
- | `float` | `number` / `float` |
362
- | `decimal` | `number` / `double` |
363
- | `string` | `string` |
364
- | `text` | `string` |
365
- | `boolean` | `boolean` |
366
- | `date` | `string` / `date` |
367
- | `datetime` | `string` / `date-time` |
368
- | `uuid` | `string` / `uuid` |
369
- | `json` / `jsonb` | `object` |
434
+ | ActiveRecord type | OpenAPI type |
435
+ | ----------------- | ------------------ |
436
+ | integer | integer / int32 |
437
+ | bigint | integer / int64 |
438
+ | float | number / float |
439
+ | decimal | number / double |
440
+ | string | string |
441
+ | text | string |
442
+ | boolean | boolean |
443
+ | date | string / date |
444
+ | datetime | string / date-time |
445
+ | uuid | string / uuid |
446
+ | json / jsonb | object |
370
447
 
371
448
  ---
372
449
 
@@ -382,7 +459,7 @@ config/routes.rb
382
459
  db/schema.rb
383
460
  ```
384
461
 
385
- The spec is automatically regenerated on the next request to `/docs/openapi.json` whenever any of these files change. No server restart needed.
462
+ The spec is automatically regenerated on the next request to /docs/openapi.json whenever any of these files change. No server restart needed.
386
463
 
387
464
  ---
388
465
 
@@ -395,4 +472,4 @@ The spec is automatically regenerated on the next request to `/docs/openapi.json
395
472
 
396
473
  ## License
397
474
 
398
- [MIT](LICENSE.txt)
475
+ MIT (LICENSE.txt)
data/README.pt-BR.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # OpenapiBlocks
2
2
 
3
- OpenapiBlocks é uma gem Rails que gera automaticamente documentação OpenAPI 3.0/3.1 a partir dos seus models ActiveRecord, validações ActiveModel e rotas do Rails — inspirada no [ActiveModel::Serializer](https://github.com/rails-api/active_model_serializers).
3
+ OpenapiBlocks é uma gem Rails que gera automaticamente documentação OpenAPI 3.0/3.1 a partir dos seus models ActiveRecord, validações ActiveModel e rotas do Rails — inspirada no ActiveModel::Serializer (https://github.com/rails-api/active_model_serializers).
4
4
 
5
- English version: [README.md](README.md)
5
+ English version: README.md
6
6
 
7
- Sem anotações manuais. Sem DSL nos controllers. Basta declarar o que expor e a spec é gerada automaticamente. Inclui um serializer de alta performance — ~3.6× mais rápido que `as_json` com escalabilidade linear de 10 a 5000 registros.
7
+ Sem anotações manuais. Sem DSL nos controllers. Basta declarar o que expor e a spec é gerada automaticamente. Inclui um serializer de alta performance — ~3.6× mais rápido que as_json com escalabilidade linear de 10 a 5000 registros.
8
8
 
9
9
  ---
10
10
 
11
11
  ## Instalação
12
12
 
13
- Adicione ao seu `Gemfile`:
13
+ Adicione ao seu Gemfile:
14
14
 
15
15
  ```ruby
16
16
  gem "openapi_blocks"
@@ -24,6 +24,70 @@ bundle install
24
24
 
25
25
  ---
26
26
 
27
+ ## Generators
28
+
29
+ O OpenapiBlocks oferece três generators para começar rapidamente.
30
+
31
+ ### Install
32
+
33
+ ```bash
34
+ rails generate openapi_blocks:install
35
+ ```
36
+
37
+ Cria `config/initializers/openapi_blocks.rb` com todas as opções disponíveis comentadas, e monta o engine no `config/routes.rb`:
38
+
39
+ ```ruby
40
+ mount OpenapiBlocks::Engine => "/docs"
41
+ ```
42
+
43
+ ### Openapi
44
+
45
+ ```bash
46
+ rails generate openapi_blocks:openapi User
47
+ ```
48
+
49
+ Cria `app/openapi/user_openapi.rb` com todas as opções de DSL disponíveis comentadas:
50
+
51
+ ```ruby
52
+ # app/openapi/user_openapi.rb
53
+ class UserOpenapi < OpenapiBlocks::Controller
54
+ # resource UserSerializer
55
+ # controller UsersController
56
+
57
+ # tags "Usuários"
58
+
59
+ # operation :index do
60
+ # summary "Lista todos os usuários"
61
+ # response 200, description: "Lista de usuários", schema: { type: :array, items: :User }
62
+ # end
63
+ end
64
+ ```
65
+
66
+ ### Serializer
67
+
68
+ ```bash
69
+ rails generate openapi_blocks:serializer User
70
+ ```
71
+
72
+ Cria `app/serializers/user_serializer.rb` com todas as opções de DSL disponíveis comentadas:
73
+
74
+ ```ruby
75
+ # app/serializers/user_serializer.rb
76
+ class UserSerializer < OpenapiBlocks::Serializer
77
+ # ignore :password_digest, :reset_password_token
78
+
79
+ # association :posts, type: :array, read_only: true
80
+ # association :company
81
+
82
+ # attribute :full_name, type: :string, read_only: true
83
+ # def full_name
84
+ # "#{object.first_name} #{object.last_name}"
85
+ # end
86
+ end
87
+ ```
88
+
89
+ ---
90
+
27
91
  ## Configuração
28
92
 
29
93
  ### 1. Monte o Engine
@@ -48,7 +112,7 @@ GET /docs/openapi.yaml -> Spec OpenAPI em YAML
48
112
 
49
113
  ### 2. Configure o initializer
50
114
 
51
- `OpenapiBlocks.configure` é obrigatório. A gem lança `OpenapiBlocks::Error` na primeira requisição se nunca foi chamado ou se `info.title` / `info.version` estiverem em branco.
115
+ OpenapiBlocks.configure é obrigatório. A gem lança OpenapiBlocks::Error na primeira requisição se nunca foi chamado ou se info.title / info.version estiverem em branco.
52
116
 
53
117
  ```ruby
54
118
  # config/initializers/openapi_blocks.rb
@@ -99,11 +163,11 @@ end
99
163
 
100
164
  ## Uso
101
165
 
102
- OpenapiBlocks oferece duas classes base com responsabilidades distintas:
166
+ O OpenapiBlocks oferece duas classes base com responsabilidades distintas:
103
167
 
104
- - `OpenapiBlocks::Serializer` — define o model, campos, associações e lógica de serialização. Fica em `app/serializers/`.
105
- - `OpenapiBlocks::Controller` — define operações, parâmetros e respostas para documentação. Fica em `app/openapi/`.
106
- - `OpenapiBlocks::Base` — classe base legada que combina ambas as responsabilidades. Ainda suportada.
168
+ - OpenapiBlocks::Serializer — define o model, campos, associações e lógica de serialização. Fica em app/serializers/.
169
+ - OpenapiBlocks::Controller — define operações, parâmetros e respostas para documentação. Fica em app/openapi/.
170
+ - OpenapiBlocks::Base — classe base legada que combina ambas as responsabilidades. Ainda suportada.
107
171
 
108
172
  ### Recomendado: Serializer + Controller
109
173
 
@@ -142,7 +206,7 @@ end
142
206
  ```ruby
143
207
  # app/openapi/user_openapi.rb
144
208
  class UserOpenapi < OpenapiBlocks::Controller
145
- resource UserSerializer
209
+ resource UserSerializer # vincula ao serializer — o schema é derivado dele
146
210
  controller UsersController
147
211
 
148
212
  tags "Usuários"
@@ -169,6 +233,19 @@ class UserOpenapi < OpenapiBlocks::Controller
169
233
  end
170
234
  ```
171
235
 
236
+ #### Como o schema OpenAPI é gerado
237
+
238
+ Quando `resource UserSerializer` é declarado em um `Controller`, o OpenapiBlocks deriva o schema OpenAPI diretamente do serializer — não do model. Isso garante que o que está documentado é exatamente o que a API retorna.
239
+
240
+ O schema é construído a partir de três fontes no serializer:
241
+
242
+ - Colunas do ActiveRecord — lidas do `db/schema.rb` via o model inferido. Os tipos das colunas são mapeados para tipos OpenAPI automaticamente.
243
+ - Declarações `attribute` — campos virtuais que não existem no banco. Campos declarados com `read_only: true` aparecem no schema de resposta `User` mas são excluídos do schema de requisição `UserInput`.
244
+ - Declarações `association` — resolvidas como `$ref` para o schema associado. Associações com `read_only: true` aparecem na resposta mas são excluídas do `UserInput`.
245
+ - Declarações `ignore` — colunas excluídas de ambos os schemas.
246
+
247
+ O schema `UserInput` (usado nos request bodies de POST, PUT e PATCH) é derivado automaticamente do schema `User` removendo `id`, `created_at`, `updated_at` e qualquer campo marcado com `read_only: true`.
248
+
172
249
  ```ruby
173
250
  # app/controllers/users_controller.rb
174
251
  def index
@@ -229,7 +306,7 @@ def show
229
306
  end
230
307
  ```
231
308
 
232
- O registro do serializer é automático por convenção (`UserSerializer` -> `User`). Para registro explícito:
309
+ O registro do serializer é automático por convenção (UserSerializer -> User). Para registro explícito:
233
310
 
234
311
  ```ruby
235
312
  class AdminUserSerializer < OpenapiBlocks::Serializer
@@ -243,34 +320,34 @@ Se nenhum serializer for encontrado, o OpenapiBlocks usa o comportamento padrão
243
320
 
244
321
  ## Serializer
245
322
 
246
- O serializer compila um método extrator monolítico por classe no boot usando `class_eval`. Sem loops, sem indireção via lambda e sem branching por objeto em tempo de execução.
323
+ O serializer compila um método extrator monolítico por classe no boot usando class_eval. Sem loops, sem indireção via lambda e sem branching por objeto em tempo de execução.
247
324
 
248
325
  ### Performance (200 registros, arm64, Ruby 4.0)
249
326
 
250
- | Método | i/s | μs/i | vs serialize |
251
- |------------|-------|------|--------------|
252
- | serialize | 4 239 | 235 | — |
327
+ | Método | i/s | us/i | vs serialize |
328
+ | ---------- | ----- | ---- | ---------------- |
329
+ | serialize | 4 239 | 235 | — |
253
330
  | to_json | 1 444 | 692 | 2.94× mais lento |
254
331
  | as_json | 1 186 | 843 | 3.58× mais lento |
255
332
  | oj+as_json | 1 126 | 888 | 3.77× mais lento |
256
333
 
257
- A escalabilidade é linear — a vantagem de 3.6× sobre o `as_json` se mantém de 10 a 5000 registros.
334
+ A escalabilidade é linear — a vantagem de 3.6× sobre o as_json se mantém de 10 a 5000 registros.
258
335
 
259
336
  ### Atributos virtuais e resolução de métodos
260
337
 
261
- | Declarado com | Método no serializer? | Chama |
262
- |------------------------|-----------------------|-----------------------------------------|
263
- | `attribute :full_name` | sim | `serializer_instance.full_name` |
264
- | `attribute :full_name` | não | `object.full_name` (delegado ao model) |
265
- | coluna no banco | — | `object.attribute` (direto) |
338
+ | Declarado com | Método no serializer? | Chama |
339
+ | -------------------- | --------------------- | ------------------------------------ |
340
+ | attribute :full_name | sim | serializer_instance.full_name |
341
+ | attribute :full_name | não | object.full_name (delegado ao model) |
342
+ | coluna no banco | — | object.attribute (direto) |
266
343
 
267
344
  ### Resolução do serializer de associações
268
345
 
269
346
  Para cada associação, o serializer resolve a classe na seguinte ordem:
270
347
 
271
- 1. `PostSerializer` — tem `serialize`, usado diretamente.
272
- 2. `PostOpenapi` — é um `Controller`, delega para o `_resource`.
273
- 3. Fallback — chama `as_json` no valor da associação.
348
+ 1. PostSerializer — tem serialize, usado diretamente.
349
+ 2. PostOpenapi — é um Controller, delega para o \_resource.
350
+ 3. Fallback — chama as_json no valor da associação.
274
351
 
275
352
  ---
276
353
 
@@ -289,14 +366,14 @@ end
289
366
 
290
367
  O OpenapiBlocks gera:
291
368
 
292
- - Schema `User` a partir das colunas e tipos do `db/schema.rb`
293
- - Schema `UserInput` para os request bodies de `POST`, `PUT` e `PATCH` (sem `id`, `created_at`, `updated_at` e campos `read_only`)
294
- - Campos `required` a partir das validações `presence: true`
295
- - `minLength`, `maxLength` a partir das validações `length`
296
- - `minimum`, `maximum` a partir das validações `numericality`
297
- - `enum` a partir das validações `inclusion`
298
- - `format: "email"` a partir das validações de formato
299
- - Todos os paths a partir do `config/routes.rb`
369
+ - Schema User a partir das colunas e tipos do db/schema.rb
370
+ - Schema UserInput para os request bodies de POST, PUT e PATCH (sem id, created_at, updated_at e campos read_only)
371
+ - Campos required a partir das validações presence: true
372
+ - minLength, maxLength a partir das validações length
373
+ - minimum, maximum a partir das validações numericality
374
+ - enum a partir das validações inclusion
375
+ - format: "email" a partir das validações de formato
376
+ - Todos os paths a partir do config/routes.rb
300
377
 
301
378
  ---
302
379
 
@@ -339,10 +416,10 @@ association :posts, type: :array, read_only: true # excluído do UserInput (som
339
416
 
340
417
  Atributos virtuais são campos que existem na resposta da API mas não no banco de dados.
341
418
 
342
- | Opção | Descrição | Aparece em User | Aparece em UserInput |
343
- |--------------------|----------------------------------------|:---------------:|:--------------------:|
344
- | `read_only: true` | Campos calculados ou gerados pelo sistema | SIM | NÃO |
345
- | `read_only: false` | Campos que o cliente pode enviar e receber | SIM | SIM |
419
+ | Opção | Descrição | Aparece em User | Aparece em UserInput |
420
+ | ---------------- | ------------------------------------------ | :-------------: | :------------------: |
421
+ | read_only: true | Campos calculados ou gerados pelo sistema | SIM | NÃO |
422
+ | read_only: false | Campos que o cliente pode enviar e receber | SIM | SIM |
346
423
 
347
424
  ```ruby
348
425
  attribute :full_name, type: :string, read_only: true # somente resposta
@@ -354,19 +431,19 @@ attribute :nickname, type: :string # requisição e respos
354
431
 
355
432
  ## Mapeamento de Tipos
356
433
 
357
- | Tipo ActiveRecord | Tipo OpenAPI |
358
- |-------------------|------------------------|
359
- | `integer` | `integer` / `int32` |
360
- | `bigint` | `integer` / `int64` |
361
- | `float` | `number` / `float` |
362
- | `decimal` | `number` / `double` |
363
- | `string` | `string` |
364
- | `text` | `string` |
365
- | `boolean` | `boolean` |
366
- | `date` | `string` / `date` |
367
- | `datetime` | `string` / `date-time` |
368
- | `uuid` | `string` / `uuid` |
369
- | `json` / `jsonb` | `object` |
434
+ | Tipo ActiveRecord | Tipo OpenAPI |
435
+ | ----------------- | ------------------ |
436
+ | integer | integer / int32 |
437
+ | bigint | integer / int64 |
438
+ | float | number / float |
439
+ | decimal | number / double |
440
+ | string | string |
441
+ | text | string |
442
+ | boolean | boolean |
443
+ | date | string / date |
444
+ | datetime | string / date-time |
445
+ | uuid | string / uuid |
446
+ | json / jsonb | object |
370
447
 
371
448
  ---
372
449
 
@@ -382,7 +459,7 @@ config/routes.rb
382
459
  db/schema.rb
383
460
  ```
384
461
 
385
- A spec é regenerada automaticamente na próxima requisição a `/docs/openapi.json` sempre que algum desses arquivos for alterado. Sem precisar reiniciar o servidor.
462
+ A spec é regenerada automaticamente na próxima requisição a /docs/openapi.json sempre que algum desses arquivos for alterado. Sem precisar reiniciar o servidor.
386
463
 
387
464
  ---
388
465
 
@@ -395,4 +472,4 @@ A spec é regenerada automaticamente na próxima requisição a `/docs/openapi.j
395
472
 
396
473
  ## Licença
397
474
 
398
- [MIT](LICENSE.txt)
475
+ MIT (LICENSE.txt)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiBlocks
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base # rubocop:disable Style/Documentation
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates an OpenapiBlocks initializer and mounts the engine in routes.rb"
9
+
10
+ def create_initializer
11
+ template "initializer.rb.tt", "config/initializers/openapi_blocks.rb"
12
+ end
13
+
14
+ def mount_engine
15
+ route 'mount OpenapiBlocks::Engine => "/docs"'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ OpenapiBlocks.configure do |config|
4
+ # config.openapi_version = "3.1.0" # required — "3.0.3" or "3.1.0"
5
+
6
+ # config.auto_serialize = true # default is false
7
+
8
+ config.info do
9
+ title "My API" # required
10
+ version "1.0.0" # required
11
+ description "API documentation generated automatically"
12
+
13
+ # contact do
14
+ # name "My Team"
15
+ # email "api@mycompany.com"
16
+ # url "https://mycompany.com"
17
+ # end
18
+
19
+ # license do
20
+ # name "MIT"
21
+ # url "https://opensource.org/licenses/MIT"
22
+ # end
23
+ end
24
+
25
+ # config.servers do
26
+ # server do
27
+ # url "http://localhost:3000"
28
+ # description "Development"
29
+ # end
30
+ # end
31
+
32
+ # config.security do
33
+ # bearer_token format: "JWT" # Authorization: Bearer <token>
34
+ # api_key name: "X-API-Key", in: :header # X-API-Key: <key>
35
+ # end
36
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiBlocks
4
+ module Generators
5
+ class OpenapiGenerator < Rails::Generators::NamedBase # rubocop:disable Style/Documentation
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates an OpenapiBlocks Controller class in app/openapi/"
9
+
10
+ def create_openapi_file
11
+ template "openapi.rb.tt", "app/openapi/#{file_name}_openapi.rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= class_name %>Openapi < OpenapiBlocks::Controller
4
+ # resource <%= class_name %>Serializer
5
+ # controller <%= class_name %>Controller
6
+
7
+ # tags "<%= class_name.pluralize %>"
8
+
9
+ # operation :index do
10
+ # summary "List all <%= class_name.pluralize.downcase %>"
11
+ # description "Returns a paginated list of <%= class_name.pluralize.downcase %>"
12
+ #
13
+ # parameter :page, in: :query, type: :integer, description: "Page number"
14
+ # parameter :per_page, in: :query, type: :integer, description: "Items per page"
15
+ #
16
+ # response 200, description: "List of <%= class_name.pluralize.downcase %>", schema: { type: :array, items: :<%= class_name %> }
17
+ # response 401, description: "Unauthorized"
18
+ # end
19
+
20
+ # operation :show do
21
+ # summary "Get a <%= class_name.downcase %>"
22
+ #
23
+ # response 200, description: "<%= class_name %> found", schema: :<%= class_name %>
24
+ # response 404, description: "<%= class_name %> not found"
25
+ # end
26
+
27
+ # operation :create do
28
+ # summary "Create a <%= class_name.downcase %>"
29
+ #
30
+ # response 201, description: "<%= class_name %> created", schema: :<%= class_name %>
31
+ # response 422, description: "Invalid data"
32
+ # end
33
+
34
+ # operation :update do
35
+ # summary "Update a <%= class_name.downcase %>"
36
+ #
37
+ # response 200, description: "<%= class_name %> updated", schema: :<%= class_name %>
38
+ # response 404, description: "<%= class_name %> not found"
39
+ # response 422, description: "Invalid data"
40
+ # end
41
+
42
+ # operation :destroy do
43
+ # summary "Delete a <%= class_name.downcase %>"
44
+ #
45
+ # response 200, description: "<%= class_name %> deleted"
46
+ # response 404, description: "<%= class_name %> not found"
47
+ # end
48
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiBlocks
4
+ module Generators
5
+ class SerializerGenerator < Rails::Generators::NamedBase # rubocop:disable Style/Documentation
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates an OpenapiBlocks Serializer class in app/serializers/"
9
+
10
+ def create_serializer_file
11
+ template "serializer.rb.tt", "app/serializers/#{file_name}_serializer.rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= class_name %>Serializer < OpenapiBlocks::Serializer
4
+ # model <%= class_name %> is inferred automatically from the class name
5
+
6
+ # ignore :password_digest, :reset_password_token
7
+
8
+ # association :posts, type: :array, read_only: true
9
+ # association :company
10
+
11
+ # attribute :full_name, type: :string, read_only: true
12
+ # def full_name
13
+ # "#{object.first_name} #{object.last_name}"
14
+ # end
15
+ end
@@ -4,6 +4,12 @@ require "rails"
4
4
 
5
5
  module OpenapiBlocks
6
6
  class Railtie < Rails::Railtie # rubocop:disable Style/Documentation
7
+ generators do
8
+ require "generators/openapi_blocks/install/install_generator"
9
+ require "generators/openapi_blocks/openapi/openapi_generator"
10
+ require "generators/openapi_blocks/serializer/serializer_generator"
11
+ end
12
+
7
13
  initializer "openapi_blocks.autoload", before: :set_autoload_paths do |app|
8
14
  app.config.eager_load_paths << app.root.join("app/openapi")
9
15
  app.config.eager_load_paths << app.root.join("app/serializers")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiBlocks
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_blocks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Caio Santos
@@ -139,6 +139,12 @@ files:
139
139
  - Rakefile
140
140
  - app/controllers/openapi_blocks/spec_controller.rb
141
141
  - config/routes.rb
142
+ - lib/generators/openapi_blocks/install/install_generator.rb
143
+ - lib/generators/openapi_blocks/install/templates/initializer.rb.tt
144
+ - lib/generators/openapi_blocks/openapi/openapi_generator.rb
145
+ - lib/generators/openapi_blocks/openapi/templates/openapi.rb.tt
146
+ - lib/generators/openapi_blocks/serializer/serializer_generator.rb
147
+ - lib/generators/openapi_blocks/serializer/templates/serializer.rb.tt
142
148
  - lib/openapi_blocks.rb
143
149
  - lib/openapi_blocks/auto_serialize.rb
144
150
  - lib/openapi_blocks/base.rb