openapi_blocks 0.3.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 +4 -4
- data/CHANGELOG.md +45 -4
- data/README.md +188 -85
- data/README.pt-BR.md +222 -130
- data/app/controllers/openapi_blocks/spec_controller.rb +2 -2
- data/lib/generators/openapi_blocks/install/install_generator.rb +19 -0
- data/lib/generators/openapi_blocks/install/templates/initializer.rb.tt +36 -0
- data/lib/generators/openapi_blocks/openapi/openapi_generator.rb +15 -0
- data/lib/generators/openapi_blocks/openapi/templates/openapi.rb.tt +48 -0
- data/lib/generators/openapi_blocks/serializer/serializer_generator.rb +15 -0
- data/lib/generators/openapi_blocks/serializer/templates/serializer.rb.tt +15 -0
- data/lib/openapi_blocks/auto_serialize.rb +54 -0
- data/lib/openapi_blocks/base.rb +6 -35
- data/lib/openapi_blocks/builder.rb +34 -2
- data/lib/openapi_blocks/concerns/documentable.rb +26 -0
- data/lib/openapi_blocks/concerns/schemable.rb +45 -0
- data/lib/openapi_blocks/configuration.rb +8 -1
- data/lib/openapi_blocks/controller.rb +7 -27
- data/lib/openapi_blocks/railtie.rb +14 -2
- data/lib/openapi_blocks/registry.rb +76 -0
- data/lib/openapi_blocks/serialization.rb +197 -0
- data/lib/openapi_blocks/serializer.rb +12 -182
- data/lib/openapi_blocks/spec/components.rb +6 -4
- data/lib/openapi_blocks/version.rb +1 -1
- data/lib/openapi_blocks.rb +7 -3
- metadata +17 -5
- data/lib/openapi_blocks/resource.rb +0 -20
data/README.pt-BR.md
CHANGED
|
@@ -1,32 +1,10 @@
|
|
|
1
1
|
# OpenapiBlocks
|
|
2
2
|
|
|
3
|
-
OpenapiBlocks é uma gem Rails que gera automaticamente documentação OpenAPI 3.0/3.1 a partir dos seus
|
|
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
|
-
|
|
5
|
+
English version: README.md
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Versão padrão do OpenAPI: `3.1.0` (suportado: `3.1.0`, `3.0.3`).
|
|
9
|
-
- A Swagger UI é servida no caminho onde a engine foi montada e usa endpoints do mesmo origin (same-origin) para evitar CORS — a UI mostra uma lista de servidores, mas buscará o spec a partir da URL montada.
|
|
10
|
-
- A saída YAML é normalizada para chaves em string (`deep_stringify_keys`) para que o campo `openapi` seja reconhecido pelo Swagger UI.
|
|
11
|
-
- O DSL `association` usa `read_only: true` para marcar associações como somente resposta e excluí-las dos schemas `*Input`; associações/atributos `read_only` continuam presentes nas respostas.
|
|
12
|
-
- O `tags` é gerado no nível do documento a partir dos paths e pode ser customizado via `tags` nas classes e operações.
|
|
13
|
-
- Referências de schema aceitam `Symbol` (ex.: `schema: :user`) e arrays com items como símbolos (ex.: `items: :user`).
|
|
14
|
-
# OpenapiBlocks
|
|
15
|
-
|
|
16
|
-
OpenapiBlocks é uma gem Rails que gera automaticamente documentação OpenAPI 3.0/3.1 a partir dos seus modelos ActiveRecord, validações do ActiveModel e rotas do Rails — inspirada em ActiveModel::Serializer.
|
|
17
|
-
|
|
18
|
-
Sem anotações manuais. Sem ruído de DSL nos controllers. Basta declarar o que deve ser exposto e o spec é gerado automaticamente. Inclui um serializer interno de alto desempenho — aproximadamente 3.6× mais rápido que `as_json` com escalabilidade linear consistente.
|
|
19
|
-
|
|
20
|
-
## Principais mudanças (recentes)
|
|
21
|
-
- `OpenapiBlocks::Resource` e `OpenapiBlocks::Controller` foram introduzidos para separar responsabilidades de serialização e documentação.
|
|
22
|
-
- Versão padrão do OpenAPI: `3.1.0` (suportado: `3.1.0`, `3.0.3`).
|
|
23
|
-
- Scalar UI agora é servido em `/docs/scalar` ao lado da Swagger UI em `/docs`.
|
|
24
|
-
- A Swagger UI usa endpoints same-origin para evitar problemas de CORS ao usar "Try it out"; a UI mostra servidores configurados, mas busca o spec a partir da URL montada da engine.
|
|
25
|
-
- A saída YAML é normalizada para chaves em string (`deep_stringify_keys`) para que o campo `openapi` seja reconhecido pelo Swagger UI.
|
|
26
|
-
- O DSL `association` utiliza `read_only: true` para marcar associações como somente-resposta e excluí-las dos schemas `*Input`; atributos/associações `read_only` continuam presentes em respostas.
|
|
27
|
-
- `tags` são gerados no nível do documento a partir dos paths e podem ser customizados via `tags` nas classes e operações.
|
|
28
|
-
- Referências de schema aceitam `Symbol` (ex.: `schema: :user`) e arrays com `items` como símbolos (ex.: `items: :user`).
|
|
29
|
-
- O serializer compila um método extrator monolítico por classe em tempo de boot usando `class_eval`, eliminando ramificações por objeto e chamadas lambda em tempo de execução.
|
|
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.
|
|
30
8
|
|
|
31
9
|
---
|
|
32
10
|
|
|
@@ -46,9 +24,73 @@ bundle install
|
|
|
46
24
|
|
|
47
25
|
---
|
|
48
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
|
+
|
|
49
91
|
## Configuração
|
|
50
92
|
|
|
51
|
-
### 1. Monte
|
|
93
|
+
### 1. Monte o Engine
|
|
52
94
|
|
|
53
95
|
```ruby
|
|
54
96
|
# config/routes.rb
|
|
@@ -62,28 +104,30 @@ end
|
|
|
62
104
|
Isso expõe:
|
|
63
105
|
|
|
64
106
|
```
|
|
65
|
-
GET /docs -> Scalar UI
|
|
107
|
+
GET /docs -> Scalar UI (padrão)
|
|
66
108
|
GET /docs/swagger -> Swagger UI
|
|
67
|
-
GET /docs/openapi.json -> OpenAPI
|
|
68
|
-
GET /docs/openapi.yaml -> OpenAPI
|
|
109
|
+
GET /docs/openapi.json -> Spec OpenAPI em JSON
|
|
110
|
+
GET /docs/openapi.yaml -> Spec OpenAPI em YAML
|
|
69
111
|
```
|
|
70
112
|
|
|
71
113
|
### 2. Configure o initializer
|
|
72
114
|
|
|
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.
|
|
116
|
+
|
|
73
117
|
```ruby
|
|
74
118
|
# config/initializers/openapi_blocks.rb
|
|
75
119
|
OpenapiBlocks.configure do |config|
|
|
76
|
-
config.openapi_version = "3.1.0" # "3.0.3" ou "3.1.0"
|
|
120
|
+
config.openapi_version = "3.1.0" # obrigatório — "3.0.3" ou "3.1.0"
|
|
77
121
|
|
|
78
122
|
config.info do
|
|
79
|
-
title "Minha API"
|
|
80
|
-
version "1.0.0"
|
|
81
|
-
description "Documentação
|
|
123
|
+
title "Minha API" # obrigatório
|
|
124
|
+
version "1.0.0" # obrigatório
|
|
125
|
+
description "Documentação gerada automaticamente"
|
|
82
126
|
|
|
83
127
|
contact do
|
|
84
|
-
name "
|
|
85
|
-
email "api@
|
|
86
|
-
url "https://
|
|
128
|
+
name "Meu Time"
|
|
129
|
+
email "api@minhaempresa.com.br"
|
|
130
|
+
url "https://minhaempresa.com.br"
|
|
87
131
|
end
|
|
88
132
|
|
|
89
133
|
license do
|
|
@@ -94,7 +138,7 @@ OpenapiBlocks.configure do |config|
|
|
|
94
138
|
|
|
95
139
|
config.servers do
|
|
96
140
|
server do
|
|
97
|
-
url "https://api.
|
|
141
|
+
url "https://api.minhaempresa.com.br"
|
|
98
142
|
description "Produção"
|
|
99
143
|
end
|
|
100
144
|
|
|
@@ -104,7 +148,8 @@ OpenapiBlocks.configure do |config|
|
|
|
104
148
|
end
|
|
105
149
|
end
|
|
106
150
|
|
|
107
|
-
config.watch
|
|
151
|
+
config.watch = :development # recarrega automaticamente em desenvolvimento
|
|
152
|
+
config.auto_serialize = true # opcional — veja Serialização Automática abaixo
|
|
108
153
|
|
|
109
154
|
# opcional: esquemas de segurança
|
|
110
155
|
config.security do
|
|
@@ -118,27 +163,28 @@ end
|
|
|
118
163
|
|
|
119
164
|
## Uso
|
|
120
165
|
|
|
121
|
-
OpenapiBlocks
|
|
166
|
+
O OpenapiBlocks oferece duas classes base com responsabilidades distintas:
|
|
122
167
|
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
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.
|
|
126
171
|
|
|
127
|
-
###
|
|
172
|
+
### Recomendado: Serializer + Controller
|
|
128
173
|
|
|
129
174
|
```
|
|
130
175
|
app/
|
|
176
|
+
serializers/
|
|
177
|
+
user_serializer.rb -> serialização + schema
|
|
178
|
+
post_serializer.rb
|
|
131
179
|
openapi/
|
|
132
|
-
|
|
133
|
-
user_openapi.rb -> documentação da API
|
|
134
|
-
post_resource.rb
|
|
180
|
+
user_openapi.rb -> documentação da API
|
|
135
181
|
post_openapi.rb
|
|
136
182
|
```
|
|
137
183
|
|
|
138
184
|
```ruby
|
|
139
|
-
# app/
|
|
140
|
-
class
|
|
141
|
-
#
|
|
185
|
+
# app/serializers/user_serializer.rb
|
|
186
|
+
class UserSerializer < OpenapiBlocks::Serializer
|
|
187
|
+
# model User inferido automaticamente pelo nome da classe
|
|
142
188
|
|
|
143
189
|
ignore :password_digest, :reset_password_token
|
|
144
190
|
|
|
@@ -148,62 +194,75 @@ class UserResource < OpenapiBlocks::Resource
|
|
|
148
194
|
attribute :access_token, type: :string, read_only: true
|
|
149
195
|
attribute :nickname, type: :string
|
|
150
196
|
|
|
151
|
-
# método definido aqui — chamado na instância do
|
|
197
|
+
# método definido aqui — chamado na instância do serializer
|
|
152
198
|
def full_name
|
|
153
199
|
"#{object.name} (#{object.email})"
|
|
154
200
|
end
|
|
155
201
|
|
|
156
|
-
# ou omita o método e ele
|
|
202
|
+
# ou omita o método e ele delega para o model automaticamente
|
|
157
203
|
end
|
|
158
204
|
```
|
|
159
205
|
|
|
160
206
|
```ruby
|
|
161
207
|
# app/openapi/user_openapi.rb
|
|
162
208
|
class UserOpenapi < OpenapiBlocks::Controller
|
|
163
|
-
resource
|
|
209
|
+
resource UserSerializer # vincula ao serializer — o schema é derivado dele
|
|
164
210
|
controller UsersController
|
|
165
211
|
|
|
166
|
-
tags "
|
|
212
|
+
tags "Usuários"
|
|
167
213
|
|
|
168
214
|
operation :index do
|
|
169
|
-
summary "
|
|
170
|
-
description "
|
|
215
|
+
summary "Lista todos os usuários"
|
|
216
|
+
description "Retorna uma lista paginada de usuários ativos"
|
|
171
217
|
|
|
172
|
-
parameter :page, in: :query, type: :integer, description: "
|
|
173
|
-
parameter :per_page, in: :query, type: :integer, description: "
|
|
218
|
+
parameter :page, in: :query, type: :integer, description: "Número da página"
|
|
219
|
+
parameter :per_page, in: :query, type: :integer, description: "Itens por página"
|
|
174
220
|
|
|
175
|
-
response 200, description: "
|
|
176
|
-
response 401, description: "
|
|
221
|
+
response 200, description: "Lista de usuários", schema: { type: :array, items: :User }
|
|
222
|
+
response 401, description: "Não autorizado"
|
|
177
223
|
end
|
|
178
224
|
|
|
179
225
|
operation :show do
|
|
180
|
-
summary "
|
|
226
|
+
summary "Busca um usuário"
|
|
181
227
|
|
|
182
|
-
response 200, description: "
|
|
183
|
-
response 404, description: "
|
|
228
|
+
response 200, description: "Usuário encontrado", schema: :User
|
|
229
|
+
response 404, description: "Não encontrado"
|
|
184
230
|
|
|
185
231
|
no_security!
|
|
186
232
|
end
|
|
187
233
|
end
|
|
188
234
|
```
|
|
189
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
|
+
|
|
190
249
|
```ruby
|
|
191
250
|
# app/controllers/users_controller.rb
|
|
192
251
|
def index
|
|
193
|
-
render json:
|
|
252
|
+
render json: UserSerializer.serialize(User.includes(:posts))
|
|
194
253
|
end
|
|
195
254
|
|
|
196
255
|
def show
|
|
197
|
-
render json:
|
|
256
|
+
render json: UserSerializer.serialize(User.find(params[:id]))
|
|
198
257
|
end
|
|
199
258
|
```
|
|
200
259
|
|
|
201
|
-
### Base (
|
|
260
|
+
### Legado: Base (classe única)
|
|
202
261
|
|
|
203
262
|
```ruby
|
|
204
263
|
# app/openapi/user_openapi.rb
|
|
205
264
|
class UserOpenapi < OpenapiBlocks::Base
|
|
206
|
-
tags "
|
|
265
|
+
tags "Usuários"
|
|
207
266
|
|
|
208
267
|
ignore :password_digest
|
|
209
268
|
|
|
@@ -212,8 +271,8 @@ class UserOpenapi < OpenapiBlocks::Base
|
|
|
212
271
|
attribute :full_name, type: :string, read_only: true
|
|
213
272
|
|
|
214
273
|
operation :index do
|
|
215
|
-
summary "
|
|
216
|
-
response 200, description: "
|
|
274
|
+
summary "Lista todos os usuários"
|
|
275
|
+
response 200, description: "Lista de usuários", schema: { type: :array, items: :User }
|
|
217
276
|
end
|
|
218
277
|
end
|
|
219
278
|
```
|
|
@@ -227,36 +286,68 @@ end
|
|
|
227
286
|
|
|
228
287
|
---
|
|
229
288
|
|
|
289
|
+
## Serialização Automática
|
|
290
|
+
|
|
291
|
+
Quando `config.auto_serialize = true`, o OpenapiBlocks intercepta todas as chamadas `render json:` e aplica automaticamente o serializer registrado — sem precisar chamar o serializer explicitamente nos controllers.
|
|
292
|
+
|
|
293
|
+
```ruby
|
|
294
|
+
# config/initializers/openapi_blocks.rb
|
|
295
|
+
config.auto_serialize = true
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
```ruby
|
|
299
|
+
# app/controllers/users_controller.rb
|
|
300
|
+
def index
|
|
301
|
+
render json: User.all # serializado automaticamente pelo UserSerializer
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def show
|
|
305
|
+
render json: @user # serializado automaticamente pelo UserSerializer
|
|
306
|
+
end
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
O registro do serializer é automático por convenção (UserSerializer -> User). Para registro explícito:
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
class AdminUserSerializer < OpenapiBlocks::Serializer
|
|
313
|
+
serializes User # mapeia explicitamente este serializer para o model User
|
|
314
|
+
end
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Se nenhum serializer for encontrado, o OpenapiBlocks usa o comportamento padrão do Rails e registra um aviso no log.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
230
321
|
## Serializer
|
|
231
322
|
|
|
232
|
-
O serializer
|
|
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.
|
|
233
324
|
|
|
234
325
|
### Performance (200 registros, arm64, Ruby 4.0)
|
|
235
326
|
|
|
236
|
-
| Método
|
|
237
|
-
|
|
238
|
-
| serialize
|
|
239
|
-
| to_json
|
|
240
|
-
| as_json
|
|
241
|
-
| oj+as_json | 1 126 | 888
|
|
327
|
+
| Método | i/s | us/i | vs serialize |
|
|
328
|
+
| ---------- | ----- | ---- | ---------------- |
|
|
329
|
+
| serialize | 4 239 | 235 | — |
|
|
330
|
+
| to_json | 1 444 | 692 | 2.94× mais lento |
|
|
331
|
+
| as_json | 1 186 | 843 | 3.58× mais lento |
|
|
332
|
+
| oj+as_json | 1 126 | 888 | 3.77× mais lento |
|
|
242
333
|
|
|
243
|
-
|
|
334
|
+
A escalabilidade é linear — a vantagem de 3.6× sobre o as_json se mantém de 10 a 5000 registros.
|
|
244
335
|
|
|
245
|
-
### Atributos virtuais e resolução de
|
|
336
|
+
### Atributos virtuais e resolução de métodos
|
|
246
337
|
|
|
247
|
-
| Declarado com
|
|
248
|
-
|
|
249
|
-
|
|
|
250
|
-
|
|
|
251
|
-
| coluna no
|
|
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) |
|
|
252
343
|
|
|
253
|
-
### Resolução
|
|
344
|
+
### Resolução do serializer de associações
|
|
254
345
|
|
|
255
|
-
Para cada associação, a
|
|
346
|
+
Para cada associação, o serializer resolve a classe na seguinte ordem:
|
|
256
347
|
|
|
257
|
-
1.
|
|
258
|
-
2.
|
|
259
|
-
3. Fallback — chama
|
|
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.
|
|
260
351
|
|
|
261
352
|
---
|
|
262
353
|
|
|
@@ -273,16 +364,16 @@ class User < ApplicationRecord
|
|
|
273
364
|
end
|
|
274
365
|
```
|
|
275
366
|
|
|
276
|
-
OpenapiBlocks gera:
|
|
367
|
+
O OpenapiBlocks gera:
|
|
277
368
|
|
|
278
|
-
-
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
285
|
-
- Todos os paths a partir
|
|
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
|
|
286
377
|
|
|
287
378
|
---
|
|
288
379
|
|
|
@@ -292,20 +383,20 @@ Configure esquemas de segurança globais no initializer:
|
|
|
292
383
|
|
|
293
384
|
```ruby
|
|
294
385
|
config.security do
|
|
295
|
-
bearer_token format: "JWT"
|
|
296
|
-
api_key name: "X-API-Key", in: :header
|
|
386
|
+
bearer_token format: "JWT" # Authorization: Bearer <token>
|
|
387
|
+
api_key name: "X-API-Key", in: :header # X-API-Key: <key>
|
|
297
388
|
end
|
|
298
389
|
```
|
|
299
390
|
|
|
300
|
-
|
|
391
|
+
Sobrescreva a segurança por operação:
|
|
301
392
|
|
|
302
393
|
```ruby
|
|
303
394
|
operation :index do
|
|
304
|
-
security :bearerAuth
|
|
395
|
+
security :bearerAuth # só bearer nesta operação
|
|
305
396
|
end
|
|
306
397
|
|
|
307
398
|
operation :show do
|
|
308
|
-
no_security!
|
|
399
|
+
no_security! # endpoint público — sem autenticação
|
|
309
400
|
end
|
|
310
401
|
```
|
|
311
402
|
|
|
@@ -314,60 +405,61 @@ end
|
|
|
314
405
|
## Associações
|
|
315
406
|
|
|
316
407
|
```ruby
|
|
317
|
-
association :company
|
|
318
|
-
association :posts, type: :array
|
|
319
|
-
association :posts, type: :array, read_only: true
|
|
408
|
+
association :company # belongs_to — $ref para schema Company
|
|
409
|
+
association :posts, type: :array # has_many — array de $ref para schema Post
|
|
410
|
+
association :posts, type: :array, read_only: true # excluído do UserInput (somente resposta)
|
|
320
411
|
```
|
|
321
412
|
|
|
322
413
|
---
|
|
323
414
|
|
|
324
415
|
## Atributos Virtuais
|
|
325
416
|
|
|
326
|
-
Atributos virtuais são campos que existem
|
|
417
|
+
Atributos virtuais são campos que existem na resposta da API mas não no banco de dados.
|
|
327
418
|
|
|
328
|
-
| Opção
|
|
329
|
-
|
|
330
|
-
|
|
|
331
|
-
|
|
|
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 |
|
|
332
423
|
|
|
333
424
|
```ruby
|
|
334
|
-
attribute :full_name, type: :string, read_only: true
|
|
335
|
-
attribute :access_token, type: :string, read_only: true
|
|
336
|
-
attribute :nickname, type: :string
|
|
425
|
+
attribute :full_name, type: :string, read_only: true # somente resposta
|
|
426
|
+
attribute :access_token, type: :string, read_only: true # somente resposta
|
|
427
|
+
attribute :nickname, type: :string # requisição e resposta
|
|
337
428
|
```
|
|
338
429
|
|
|
339
430
|
---
|
|
340
431
|
|
|
341
|
-
## Mapeamento de
|
|
342
|
-
|
|
343
|
-
| Tipo
|
|
344
|
-
|
|
345
|
-
| integer
|
|
346
|
-
| bigint
|
|
347
|
-
| float
|
|
348
|
-
| decimal
|
|
349
|
-
| string
|
|
350
|
-
| text
|
|
351
|
-
| boolean
|
|
352
|
-
| date
|
|
353
|
-
| datetime
|
|
354
|
-
| uuid
|
|
355
|
-
| json / jsonb
|
|
432
|
+
## Mapeamento de Tipos
|
|
433
|
+
|
|
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 |
|
|
356
447
|
|
|
357
448
|
---
|
|
358
449
|
|
|
359
|
-
##
|
|
450
|
+
## Recarregamento Automático em Desenvolvimento
|
|
360
451
|
|
|
361
|
-
OpenapiBlocks
|
|
452
|
+
O OpenapiBlocks monitora mudanças em:
|
|
362
453
|
|
|
363
454
|
```
|
|
455
|
+
app/serializers/**/*.rb
|
|
364
456
|
app/openapi/**/*.rb
|
|
365
457
|
app/models/**/*.rb
|
|
366
458
|
config/routes.rb
|
|
367
459
|
db/schema.rb
|
|
368
460
|
```
|
|
369
461
|
|
|
370
|
-
|
|
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.
|
|
371
463
|
|
|
372
464
|
---
|
|
373
465
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "action_controller/api"
|
|
4
4
|
|
|
5
5
|
module OpenapiBlocks
|
|
6
|
-
class SpecController < ActionController::API # rubocop:disable Style/Documentation
|
|
6
|
+
class SpecController < ActionController::API # rubocop:disable Style/Documentation,Metrics/ClassLength
|
|
7
7
|
SWAGGER_UI_CSS = "https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css"
|
|
8
8
|
SWAGGER_UI_STANDALONE_JS = "https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-standalone-preset.js"
|
|
9
9
|
SWAGGER_UI_JS = "https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js"
|
|
@@ -30,7 +30,7 @@ module OpenapiBlocks
|
|
|
30
30
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
|
-
def scalar_html
|
|
33
|
+
def scalar_html # rubocop:disable Metrics/MethodLength
|
|
34
34
|
spec_url = "#{swagger_spec_base_url}.json"
|
|
35
35
|
title = "#{OpenapiBlocks.configuration.info.title} - Scalar"
|
|
36
36
|
|
|
@@ -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
|