apicasso 0.4.5 → 0.4.6
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 +5 -5
- data/README.md +226 -223
- data/Rakefile +23 -23
- data/app/controllers/apicasso/apidocs_controller.rb +309 -299
- data/app/controllers/apicasso/application_controller.rb +170 -147
- data/app/controllers/apicasso/crud_controller.rb +246 -245
- data/app/controllers/concerns/orderable.rb +45 -45
- data/app/models/apicasso/ability.rb +38 -38
- data/app/models/apicasso/application_record.rb +6 -6
- data/app/models/apicasso/key.rb +25 -25
- data/app/models/apicasso/request.rb +8 -8
- data/config/routes.rb +14 -14
- data/lib/apicasso/active_record_extension.rb +0 -44
- data/lib/apicasso/engine.rb +13 -13
- data/lib/apicasso/version.rb +3 -3
- data/lib/apicasso.rb +15 -13
- data/lib/generators/apicasso/install/install_generator.rb +25 -25
- data/lib/generators/apicasso/install/templates/create_apicasso_tables.rb +20 -20
- data/spec/dummy/Gemfile +56 -0
- data/spec/dummy/Gemfile.lock +237 -0
- data/spec/dummy/app/controllers/application_controller.rb +1 -1
- data/spec/dummy/app/models/used_model.rb +42 -0
- data/spec/dummy/app/serializers/used_model_serializer.rb +3 -0
- data/spec/dummy/bin/rails +5 -0
- data/spec/dummy/bin/rake +5 -0
- data/spec/dummy/bin/setup +0 -3
- data/spec/dummy/bin/spring +17 -0
- data/spec/dummy/bin/update +0 -3
- data/spec/dummy/config/application.rb +14 -10
- data/spec/dummy/config/cable.yml +1 -1
- data/spec/dummy/config/credentials.yml.enc +1 -0
- data/spec/dummy/config/database.yml +5 -14
- data/spec/dummy/config/environments/development.rb +6 -10
- data/spec/dummy/config/environments/production.rb +1 -10
- data/spec/dummy/config/initializers/cors.rb +16 -0
- data/spec/dummy/config/locales/en.yml +7 -32
- data/spec/dummy/config/routes.rb +1 -1
- data/{db/migrate/20180826141433_create_apicasso_tables.rb → spec/dummy/db/migrate/20180918134607_create_apicasso_tables.rb} +1 -0
- data/spec/dummy/db/migrate/20180918141254_create_used_models.rb +44 -0
- data/spec/dummy/db/migrate/20180919130152_create_active_storage_tables.active_storage.rb +26 -0
- data/spec/dummy/db/migrate/20180920133933_change_used_model_to_validates.rb +7 -0
- data/spec/dummy/db/schema.rb +98 -0
- data/spec/dummy/db/seeds.rb +56 -0
- data/spec/factories/used_model.rb +28 -0
- data/spec/models/used_model_spec.rb +35 -0
- data/spec/rails_helper.rb +66 -0
- data/spec/requests/requests_spec.rb +227 -0
- data/spec/spec_helper.rb +7 -9
- data/spec/support/factory_bot.rb +3 -0
- metadata +83 -64
- data/spec/controllers/apicasso/aplication_controller_spec.rb +0 -18
- data/spec/controllers/apicasso/crud_controller_spec.rb +0 -107
- data/spec/dummy/app/assets/config/manifest.js +0 -3
- data/spec/dummy/app/assets/javascripts/application.js +0 -15
- data/spec/dummy/app/assets/javascripts/cable.js +0 -13
- data/spec/dummy/app/assets/stylesheets/application.css +0 -15
- data/spec/dummy/app/channels/application_cable/channel.rb +0 -4
- data/spec/dummy/app/channels/application_cable/connection.rb +0 -4
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
- data/spec/dummy/app/jobs/application_job.rb +0 -2
- data/spec/dummy/app/mailers/application_mailer.rb +0 -4
- data/spec/dummy/app/views/layouts/application.html.erb +0 -15
- data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
- data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
- data/spec/dummy/bin/yarn +0 -11
- data/spec/dummy/config/initializers/assets.rb +0 -14
- data/spec/dummy/config/initializers/content_security_policy.rb +0 -25
- data/spec/dummy/config/initializers/cookies_serializer.rb +0 -5
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/public/404.html +0 -67
- data/spec/dummy/public/422.html +0 -67
- data/spec/dummy/public/500.html +0 -66
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/apicasso_key.rb +0 -9
- data/spec/factories/object.rb +0 -5
- data/spec/models/apicasso/key.rb +0 -5
- data/spec/routing/appointments_routing_spec.rb +0 -38
@@ -3,14 +3,17 @@
|
|
3
3
|
module Apicasso
|
4
4
|
# Controller used to generate an application Swagger JSON, used by
|
5
5
|
# SwaggerUI to generate beautiful API documentation
|
6
|
-
class ApidocsController <
|
6
|
+
class ApidocsController < Apicasso::ApplicationController
|
7
|
+
skip_before_action :restrict_access
|
8
|
+
|
7
9
|
include Swagger::Blocks
|
8
10
|
|
9
11
|
swagger_root do
|
12
|
+
MODELS_EXCLUDED = [::ApplicationRecord, ActiveRecord::SchemaMigration, Apicasso::ApplicationRecord, Apicasso::Key, Apicasso::Request, Apicasso::ApidocsController, ActiveStorage::Attachment, ActiveStorage::Blob].freeze
|
10
13
|
key :swagger, '2.0'
|
11
14
|
info do
|
12
|
-
key :version, ENV.fetch('VERSION', I18n.t('application.version'))
|
13
15
|
key :title, ENV.fetch('APP_NAME', I18n.t('application.name'))
|
16
|
+
key 'x-logo', { url: I18n.t('app.logo.url', default: 'https://raw.githubusercontent.com/ErvalhouS/APIcasso/master/APIcasso.png'), altText: I18n.t('app.logo.alttext', default: 'Application Logo')}
|
14
17
|
key :description, ENV.fetch('APP_DESCRIPTION', I18n.t('application.description'))
|
15
18
|
key :termsOfService, I18n.t('application.terms_of_service')
|
16
19
|
contact do
|
@@ -21,15 +24,23 @@ module Apicasso
|
|
21
24
|
end
|
22
25
|
end
|
23
26
|
ActiveRecord::Base.descendants.each do |model|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
unless MODELS_EXCLUDED.include?(model)
|
28
|
+
tag do
|
29
|
+
key :name, I18n.t("activerecord.models.#{model.name.underscore}", default: model.name.underscore)
|
30
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.description", default: model.name)
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
key :host, I18n.t('application.apicasso_host', default: ENV.fetch('ROOT', 'localhost:3000'))
|
30
35
|
key :basePath, I18n.t('application.apicasso_path', default: '/')
|
31
36
|
key :consumes, ['application/json']
|
32
37
|
key :produces, ['application/json']
|
38
|
+
|
39
|
+
security_definition :api_key do
|
40
|
+
key :type, :apiKey
|
41
|
+
key :name, :api_key
|
42
|
+
key :in, :header
|
43
|
+
end
|
33
44
|
end
|
34
45
|
|
35
46
|
# Eager load application to be able to list all models
|
@@ -40,7 +51,6 @@ module Apicasso
|
|
40
51
|
*ActiveRecord::Base.descendants,
|
41
52
|
self
|
42
53
|
].freeze
|
43
|
-
|
44
54
|
swagger_schema :ErrorModel do
|
45
55
|
key :required, [:code, :message]
|
46
56
|
property :code do
|
@@ -52,277 +62,58 @@ module Apicasso
|
|
52
62
|
end
|
53
63
|
end
|
54
64
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
key :
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
key :tags, [model.name.underscore]
|
63
|
-
parameter do
|
64
|
-
key :name, :sort
|
65
|
-
key :in, :query
|
66
|
-
key :description, I18n.t('apicasso.sort.description',
|
67
|
-
default: 'Parameters sorting splitted by `,` preffixed by `+` or `-` which translates into ascending or descending order')
|
68
|
-
key :required, false
|
69
|
-
key :type, :string
|
70
|
-
key :collectionFormat, :json
|
71
|
-
end
|
72
|
-
parameter do
|
73
|
-
key :name, :q
|
74
|
-
key :in, :query
|
75
|
-
key :description, I18n.t('apicasso.q.description',
|
76
|
-
default: 'Records filtering by attribute and search query as affix. Usage: `?q[{attribute}{search_affix}]={matcher}`. All available search affixes are listed on: https://github.com/activerecord-hackery/ransack#search-matchers')
|
77
|
-
key :required, false
|
78
|
-
key :type, :json
|
79
|
-
end
|
80
|
-
parameter do
|
81
|
-
key :name, :page
|
82
|
-
key :in, :query
|
83
|
-
key :description, I18n.t('apicasso.page.description',
|
84
|
-
default: 'Records pagination paging, which offsets collection based on `params[:per_page]`')
|
85
|
-
key :required, false
|
86
|
-
key :type, :integer
|
87
|
-
end
|
88
|
-
parameter do
|
89
|
-
key :name, :per_page
|
90
|
-
key :in, :query
|
91
|
-
key :description, I18n.t('apicasso.per_page.description',
|
92
|
-
default: 'Records pagination size, which sets how many records will be rendered per request')
|
93
|
-
key :required, false
|
94
|
-
key :type, :integer
|
95
|
-
end
|
96
|
-
response 200 do
|
97
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.index.response",
|
98
|
-
default: "#{model.name} response, which include records matching current query and pagination metadata")
|
99
|
-
parameter do
|
100
|
-
key :name, :total
|
101
|
-
key :description, I18n.t('apicasso.total.description',
|
102
|
-
default: 'Total records contained in current collection, as if there was no pagination.')
|
103
|
-
key :required, true
|
104
|
-
key :type, :integer
|
105
|
-
end
|
106
|
-
parameter do
|
107
|
-
key :name, :total_pages
|
108
|
-
key :description, I18n.t('apicasso.total_pages.description',
|
109
|
-
default: 'How many pages of data the current collection has.')
|
110
|
-
key :required, true
|
111
|
-
key :type, :integer
|
112
|
-
end
|
113
|
-
parameter do
|
114
|
-
key :name, :last_page
|
115
|
-
key :description, I18n.t('apicasso.last_page.description',
|
116
|
-
default: 'An indication if current request is the last to paginate in the current collection')
|
117
|
-
key :required, true
|
118
|
-
key :type, :boolean
|
119
|
-
end
|
120
|
-
parameter do
|
121
|
-
key :name, :previous_page
|
122
|
-
key :description, I18n.t('apicasso.previous_page.description',
|
123
|
-
default: "The link of the previous page for the current collection. It can be null if there isn't any")
|
124
|
-
key :required, false
|
125
|
-
key :type, :string
|
126
|
-
end
|
127
|
-
parameter do
|
128
|
-
key :name, :next_page
|
129
|
-
key :description, I18n.t('apicasso.next_page.description',
|
130
|
-
default: "The link of the next page for the current collection. It can be null if there isn't any")
|
131
|
-
key :required, false
|
132
|
-
key :type, :string
|
133
|
-
end
|
134
|
-
parameter do
|
135
|
-
key :name, :out_of_bounds
|
136
|
-
key :description, I18n.t('apicasso.out_of_bounds.description',
|
137
|
-
default: 'An indication if current request is out of pagination bounds for the current collection')
|
138
|
-
key :required, true
|
139
|
-
key :type, :boolean
|
140
|
-
end
|
141
|
-
parameter do
|
142
|
-
key :name, :offset
|
143
|
-
key :description, I18n.t('apicasso.offset.description',
|
144
|
-
default: 'How many records were offsetted from the collection to render the current page')
|
145
|
-
key :required, true
|
146
|
-
key :type, :integer
|
147
|
-
end
|
148
|
-
parameter do
|
149
|
-
key :name, :entries
|
150
|
-
key :description, I18n.t('apicasso.entries.description',
|
151
|
-
default: 'The records collection in the current pagination scope.')
|
152
|
-
key :required, true
|
153
|
-
key :type, :array
|
154
|
-
items do
|
155
|
-
key :'$ref', model.name.to_sym
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
response :default do
|
160
|
-
key :description, I18n.t("activerecord.errors.models.#{model.name.underscore}",
|
161
|
-
default: "Unexpected error in #{model.name}")
|
162
|
-
schema do
|
163
|
-
key :'$ref', :ErrorModel
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
operation :options do
|
168
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.schema.description",
|
169
|
-
default: "#{model.name} metadata information.")
|
170
|
-
key :operationId, "schema#{model.name.pluralize}"
|
171
|
-
key :produces, ['application/json']
|
172
|
-
key :tags, [model.name.underscore]
|
173
|
-
response 200 do
|
174
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.schema.response",
|
175
|
-
default: "#{model.name} metadata as a json with field names as keys and field types as values.")
|
176
|
-
schema do
|
177
|
-
key :'$ref', "#{model.name}Metadata".to_sym
|
178
|
-
end
|
179
|
-
end
|
180
|
-
response :default do
|
181
|
-
key :description, I18n.t("activerecord.errors.models.#{model.name.underscore}",
|
182
|
-
default: "Unexpected error in #{model.name}")
|
183
|
-
schema do
|
184
|
-
key :'$ref', :ErrorModel
|
65
|
+
SWAGGERED_CLASSES.each do |klass|
|
66
|
+
unless MODELS_EXCLUDED.include?(klass)
|
67
|
+
swagger_schema klass.name.to_sym do
|
68
|
+
key :required, klass.presence_validators if klass.presence_validators?
|
69
|
+
klass.columns_hash.each do |name, type|
|
70
|
+
property name.to_sym do
|
71
|
+
key :type, type.type
|
185
72
|
end
|
186
73
|
end
|
187
74
|
end
|
188
|
-
|
189
|
-
|
190
|
-
default: "Creates a #{model.name}")
|
191
|
-
key :operationId, "add#{model.name}"
|
192
|
-
key :produces, ['application/json']
|
193
|
-
key :tags, [model.name.underscore]
|
194
|
-
parameter do
|
195
|
-
key :name, model.name.underscore.to_sym
|
196
|
-
key :in, :body
|
197
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.create.description",
|
198
|
-
default: "#{model.name} to add into application")
|
199
|
-
key :required, true
|
75
|
+
swagger_schema "#{klass.name}Input".to_sym do
|
76
|
+
allOf do
|
200
77
|
schema do
|
201
|
-
key :'$ref', "#{
|
78
|
+
key :'$ref', "#{klass.name}Input".to_sym
|
202
79
|
end
|
203
|
-
end
|
204
|
-
response 201 do
|
205
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.description",
|
206
|
-
default: "#{model.name} response")
|
207
|
-
schema do
|
208
|
-
key :'$ref', model.name.to_sym
|
209
|
-
end
|
210
|
-
end
|
211
|
-
response :default do
|
212
|
-
key :description, I18n.t("activerecord.errors.models.#{model.name.underscore}",
|
213
|
-
default: "Unexpected error in #{model.name}")
|
214
|
-
schema do
|
215
|
-
key :'$ref', :ErrorModel
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
swagger_path "/#{model.name.underscore}/{id}" do
|
221
|
-
operation :patch do
|
222
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.update.response",
|
223
|
-
default: "Updates a #{model.name}")
|
224
|
-
key :operationId, "edit#{model.name}"
|
225
|
-
key :produces, ['application/json']
|
226
|
-
key :tags, [model.name.underscore]
|
227
|
-
parameter do
|
228
|
-
key :name, :id
|
229
|
-
key :in, :path
|
230
|
-
key :description, I18n.t("activerecord.models.attributes.#{model.name.underscore}.id",
|
231
|
-
default: "ID of #{model.name} to update on the application")
|
232
|
-
key :required, true
|
233
80
|
schema do
|
234
|
-
key :
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.update.description",
|
241
|
-
default: "Existing #{model.name} to update on the application")
|
242
|
-
key :required, true
|
243
|
-
schema do
|
244
|
-
key :'$ref', "#{model.name}Input".to_sym
|
245
|
-
end
|
246
|
-
end
|
247
|
-
response 200 do
|
248
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.description",
|
249
|
-
default: "#{model.name} response")
|
250
|
-
schema do
|
251
|
-
key :'$ref', model.name.to_sym
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
operation :get do
|
256
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.response",
|
257
|
-
default: "Creates a #{model.name}")
|
258
|
-
key :operationId, "show#{model.name}"
|
259
|
-
key :produces, ['application/json']
|
260
|
-
key :tags, [model.name.underscore]
|
261
|
-
parameter do
|
262
|
-
key :name, :id
|
263
|
-
key :in, :path
|
264
|
-
key :description, I18n.t("activerecord.models.attributes.#{model.name.underscore}.id",
|
265
|
-
default: "ID of #{model.name} to fetch on the application")
|
266
|
-
key :required, true
|
267
|
-
schema do
|
268
|
-
key :'$ref', "#{model.name}Input".to_sym
|
269
|
-
end
|
270
|
-
end
|
271
|
-
response 200 do
|
272
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.description",
|
273
|
-
default: "#{model.name} response")
|
274
|
-
schema do
|
275
|
-
key :'$ref', model.name.to_sym
|
276
|
-
end
|
277
|
-
end
|
278
|
-
response :default do
|
279
|
-
key :description, I18n.t("activerecord.errors.models.#{model.name.underscore}",
|
280
|
-
default: "Unexpected error in #{model.name}")
|
281
|
-
schema do
|
282
|
-
key :'$ref', :ErrorModel
|
81
|
+
key :required, %i[*presence_validators] if klass.presence_validators?
|
82
|
+
klass.columns_hash.each do |name, type|
|
83
|
+
property name.to_sym do
|
84
|
+
key :type, type.type
|
85
|
+
end
|
86
|
+
end
|
283
87
|
end
|
284
88
|
end
|
285
89
|
end
|
286
|
-
|
287
|
-
|
288
|
-
default: "Deletes a #{model.name}")
|
289
|
-
key :operationId, "destroy#{model.name}"
|
290
|
-
key :produces, ['application/json']
|
291
|
-
key :tags, [model.name.underscore]
|
292
|
-
parameter do
|
293
|
-
key :name, :id
|
294
|
-
key :in, :path
|
295
|
-
key :description, I18n.t("activerecord.models.attributes.#{model.name.underscore}.id",
|
296
|
-
default: "ID of #{model.name} to delete on the application")
|
297
|
-
key :required, true
|
90
|
+
swagger_schema "#{klass.name}Metadata".to_sym do
|
91
|
+
allOf do
|
298
92
|
schema do
|
299
|
-
key :'$ref', "#{
|
93
|
+
key :'$ref', "#{klass.name}Metadata".to_sym
|
300
94
|
end
|
301
|
-
end
|
302
|
-
response 200 do
|
303
|
-
key :description, I18n.t("activerecord.models.#{model.name.underscore}.destroy.description",
|
304
|
-
default: "#{model.name} response")
|
305
|
-
end
|
306
|
-
response :default do
|
307
|
-
key :description, I18n.t("activerecord.errors.models.#{model.name.underscore}",
|
308
|
-
default: "Unexpected error in #{model.name}")
|
309
95
|
schema do
|
310
|
-
|
96
|
+
klass.columns_hash.each do |name, type|
|
97
|
+
property name.to_sym do
|
98
|
+
key :description, type.type
|
99
|
+
key :type, :string
|
100
|
+
end
|
101
|
+
end
|
311
102
|
end
|
312
103
|
end
|
313
104
|
end
|
314
105
|
end
|
106
|
+
end
|
315
107
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
swagger_path "/#{model.name.underscore}/{id}/#{association}" do
|
108
|
+
ActiveRecord::Base.descendants.each do |model|
|
109
|
+
unless MODELS_EXCLUDED.include?(model)
|
110
|
+
swagger_path "/#{model.name.underscore}" do
|
320
111
|
operation :get do
|
321
|
-
key :summary, I18n.t("activerecord.models.#{
|
322
|
-
key :description, I18n.t("activerecord.models.#{
|
323
|
-
key :operationId, "find#{
|
112
|
+
key :summary, I18n.t("activerecord.models.#{model.name.underscore}.index.summary", default: model.name)
|
113
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.index.description", default: model.name)
|
114
|
+
key :operationId, "find#{model.name.pluralize}"
|
324
115
|
key :produces, ['application/json']
|
325
|
-
key :tags, [
|
116
|
+
key :tags, [model.name.underscore]
|
326
117
|
parameter do
|
327
118
|
key :name, :sort
|
328
119
|
key :in, :query
|
@@ -357,94 +148,326 @@ module Apicasso
|
|
357
148
|
key :type, :integer
|
358
149
|
end
|
359
150
|
response 200 do
|
360
|
-
key :description, I18n.t("activerecord.models.#{
|
361
|
-
default: "#{
|
362
|
-
|
151
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.index.response",
|
152
|
+
default: "#{model.name} response, which include records matching current query and pagination metadata")
|
153
|
+
schema do
|
363
154
|
key :name, :total
|
364
155
|
key :description, I18n.t('apicasso.total.description',
|
365
156
|
default: 'Total records contained in current collection, as if there was no pagination.')
|
366
157
|
key :required, true
|
367
158
|
key :type, :integer
|
368
159
|
end
|
369
|
-
|
160
|
+
schema do
|
370
161
|
key :name, :total_pages
|
371
162
|
key :description, I18n.t('apicasso.total_pages.description',
|
372
163
|
default: 'How many pages of data the current collection has.')
|
373
164
|
key :required, true
|
374
165
|
key :type, :integer
|
375
166
|
end
|
376
|
-
|
167
|
+
schema do
|
377
168
|
key :name, :last_page
|
378
169
|
key :description, I18n.t('apicasso.last_page.description',
|
379
170
|
default: 'An indication if current request is the last to paginate in the current collection')
|
380
171
|
key :required, true
|
381
172
|
key :type, :boolean
|
382
173
|
end
|
383
|
-
|
174
|
+
schema do
|
384
175
|
key :name, :previous_page
|
385
176
|
key :description, I18n.t('apicasso.previous_page.description',
|
386
177
|
default: "The link of the previous page for the current collection. It can be null if there isn't any")
|
387
178
|
key :required, false
|
388
179
|
key :type, :string
|
389
180
|
end
|
390
|
-
|
181
|
+
schema do
|
391
182
|
key :name, :next_page
|
392
183
|
key :description, I18n.t('apicasso.next_page.description',
|
393
184
|
default: "The link of the next page for the current collection. It can be null if there isn't any")
|
394
185
|
key :required, false
|
395
186
|
key :type, :string
|
396
187
|
end
|
397
|
-
|
188
|
+
schema do
|
398
189
|
key :name, :out_of_bounds
|
399
190
|
key :description, I18n.t('apicasso.out_of_bounds.description',
|
400
191
|
default: 'An indication if current request is out of pagination bounds for the current collection')
|
401
192
|
key :required, true
|
402
193
|
key :type, :boolean
|
403
194
|
end
|
404
|
-
|
195
|
+
schema do
|
405
196
|
key :name, :offset
|
406
197
|
key :description, I18n.t('apicasso.offset.description',
|
407
198
|
default: 'How many records were offsetted from the collection to render the current page')
|
408
199
|
key :required, true
|
409
200
|
key :type, :integer
|
410
201
|
end
|
411
|
-
|
202
|
+
schema do
|
412
203
|
key :name, :entries
|
413
204
|
key :description, I18n.t('apicasso.entries.description',
|
414
205
|
default: 'The records collection in the current pagination scope.')
|
415
206
|
key :required, true
|
416
207
|
key :type, :array
|
417
208
|
items do
|
418
|
-
key :'$ref',
|
209
|
+
key :'$ref', model.name.to_sym
|
419
210
|
end
|
420
211
|
end
|
421
212
|
end
|
422
|
-
|
423
|
-
|
424
|
-
|
213
|
+
end
|
214
|
+
operation :options do
|
215
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.schema.description",
|
216
|
+
default: "#{model.name} metadata information.")
|
217
|
+
key :operationId, "schema#{model.name.pluralize}"
|
218
|
+
key :produces, ['application/json']
|
219
|
+
key :tags, [model.name.underscore]
|
220
|
+
response 200 do
|
221
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.schema.response",
|
222
|
+
default: "#{model.name} metadata as a json with field names as keys and field types as values.")
|
425
223
|
schema do
|
426
|
-
key :'$ref',
|
224
|
+
key :'$ref', "#{model.name}".to_sym
|
427
225
|
end
|
428
226
|
end
|
429
227
|
end
|
430
|
-
operation :
|
431
|
-
key :description, I18n.t("activerecord.models.#{
|
432
|
-
default: "#{
|
433
|
-
key :operationId, "
|
228
|
+
operation :post do
|
229
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.create.response",
|
230
|
+
default: "Creates a #{model.name}")
|
231
|
+
key :operationId, "add#{model.name}"
|
434
232
|
key :produces, ['application/json']
|
435
|
-
key :tags, [
|
233
|
+
key :tags, [model.name.underscore]
|
234
|
+
parameter do
|
235
|
+
key :name, model.name.underscore.to_sym
|
236
|
+
key :in, :body
|
237
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.create.description",
|
238
|
+
default: "#{model.name} to add into application")
|
239
|
+
key :required, true
|
240
|
+
schema do
|
241
|
+
key :'$ref', "#{model.name}".to_sym
|
242
|
+
end
|
243
|
+
end
|
244
|
+
response 201 do
|
245
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.description",
|
246
|
+
default: "#{model.name} response")
|
247
|
+
schema do
|
248
|
+
key :'$ref', model.name.to_sym
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
swagger_path "/#{model.name.underscore}/{id}" do
|
254
|
+
operation :patch do
|
255
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.update.response",
|
256
|
+
default: "Updates a #{model.name}")
|
257
|
+
key :operationId, "edit#{model.name}"
|
258
|
+
key :produces, ['application/json']
|
259
|
+
key :tags, [model.name.underscore]
|
260
|
+
parameter do
|
261
|
+
key :name, :id
|
262
|
+
key :in, :path
|
263
|
+
key :description, I18n.t("activerecord.models.attributes.#{model.name.underscore}.id",
|
264
|
+
default: "ID of #{model.name} to update on the application")
|
265
|
+
key :required, true
|
266
|
+
schema do
|
267
|
+
key :'$ref', "#{model.name}".to_sym
|
268
|
+
end
|
269
|
+
end
|
270
|
+
parameter do
|
271
|
+
key :name, model.name.underscore.to_sym
|
272
|
+
key :in, :body
|
273
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.update.description",
|
274
|
+
default: "Existing #{model.name} to update on the application")
|
275
|
+
key :required, true
|
276
|
+
schema do
|
277
|
+
key :'$ref', "#{model.name}".to_sym
|
278
|
+
end
|
279
|
+
end
|
436
280
|
response 200 do
|
437
|
-
key :description, I18n.t("activerecord.models.#{
|
438
|
-
default: "#{
|
281
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.description",
|
282
|
+
default: "#{model.name} response")
|
439
283
|
schema do
|
440
|
-
key :'$ref',
|
284
|
+
key :'$ref', model.name.to_sym
|
441
285
|
end
|
442
286
|
end
|
443
|
-
|
444
|
-
|
445
|
-
|
287
|
+
end
|
288
|
+
operation :get do
|
289
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.response",
|
290
|
+
default: "Creates a #{model.name}")
|
291
|
+
key :operationId, "show#{model.name}"
|
292
|
+
key :produces, ['application/json']
|
293
|
+
key :tags, [model.name.underscore]
|
294
|
+
parameter do
|
295
|
+
key :name, :id
|
296
|
+
key :in, :path
|
297
|
+
key :description, I18n.t("activerecord.models.attributes.#{model.name.underscore}.id",
|
298
|
+
default: "ID of #{model.name} to fetch on the application")
|
299
|
+
key :required, true
|
446
300
|
schema do
|
447
|
-
key :'$ref',
|
301
|
+
key :'$ref', "#{model.name}".to_sym
|
302
|
+
end
|
303
|
+
end
|
304
|
+
response 200 do
|
305
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.show.description",
|
306
|
+
default: "#{model.name} response")
|
307
|
+
schema do
|
308
|
+
key :'$ref', model.name.to_sym
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
operation :delete do
|
313
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.destroy.response",
|
314
|
+
default: "Deletes a #{model.name}")
|
315
|
+
key :operationId, "destroy#{model.name}"
|
316
|
+
key :produces, ['application/json']
|
317
|
+
key :tags, [model.name.underscore]
|
318
|
+
parameter do
|
319
|
+
key :name, :id
|
320
|
+
key :in, :path
|
321
|
+
key :description, I18n.t("activerecord.models.attributes.#{model.name.underscore}.id",
|
322
|
+
default: "ID of #{model.name} to delete on the application")
|
323
|
+
key :required, true
|
324
|
+
schema do
|
325
|
+
key :'$ref', "#{model.name}".to_sym
|
326
|
+
end
|
327
|
+
end
|
328
|
+
response 200 do
|
329
|
+
key :description, I18n.t("activerecord.models.#{model.name.underscore}.destroy.description",
|
330
|
+
default: "#{model.name} response")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
model.reflect_on_all_associations.map(&:name).each do |association|
|
336
|
+
inner_name = model.reflect_on_all_associations.select{ |ass| ass.name == association }.first.class_name
|
337
|
+
ASSOCIATION_EXCLUDED = ['ActiveStorage::Attachment', 'ActiveStorage::Blob'].freeze
|
338
|
+
unless ASSOCIATION_EXCLUDED.include?(inner_name)
|
339
|
+
inner_klass = begin inner_name.constantize rescue NameError; false end
|
340
|
+
swagger_path "/#{model.name.underscore}/{id}/#{association}" do
|
341
|
+
operation :get do
|
342
|
+
key :summary, I18n.t("activerecord.models.#{inner_name.underscore}.index.summary", default: inner_name)
|
343
|
+
key :description, I18n.t("activerecord.models.#{inner_name.underscore}.index.description", default: inner_name)
|
344
|
+
key :operationId, "find#{inner_name.pluralize}"
|
345
|
+
key :produces, ['application/json']
|
346
|
+
key :tags, [inner_name.underscore]
|
347
|
+
parameter do
|
348
|
+
key :name, :sort
|
349
|
+
key :in, :query
|
350
|
+
key :description, I18n.t('apicasso.sort.description',
|
351
|
+
default: 'Parameters sorting splitted by `,` preffixed by `+` or `-` which translates into ascending or descending order')
|
352
|
+
key :required, false
|
353
|
+
key :type, :string
|
354
|
+
key :collectionFormat, :json
|
355
|
+
end
|
356
|
+
parameter do
|
357
|
+
key :name, :q
|
358
|
+
key :in, :query
|
359
|
+
key :description, I18n.t('apicasso.q.description',
|
360
|
+
default: 'Records filtering by attribute and search query as affix. Usage: `?q[{attribute}{search_affix}]={matcher}`. All available search affixes are listed on: https://github.com/activerecord-hackery/ransack#search-matchers')
|
361
|
+
key :required, false
|
362
|
+
key :type, :json
|
363
|
+
end
|
364
|
+
parameter do
|
365
|
+
key :name, :page
|
366
|
+
key :in, :query
|
367
|
+
key :description, I18n.t('apicasso.page.description',
|
368
|
+
default: 'Records pagination paging, which offsets collection based on `params[:per_page]`')
|
369
|
+
key :required, false
|
370
|
+
key :type, :integer
|
371
|
+
end
|
372
|
+
parameter do
|
373
|
+
key :name, :per_page
|
374
|
+
key :in, :query
|
375
|
+
key :description, I18n.t('apicasso.per_page.description',
|
376
|
+
default: 'Records pagination size, which sets how many records will be rendered per request')
|
377
|
+
key :required, false
|
378
|
+
key :type, :integer
|
379
|
+
end
|
380
|
+
response 200 do
|
381
|
+
key :description, I18n.t("activerecord.models.#{inner_name.underscore}.index.response",
|
382
|
+
default: "#{inner_name} response, which include records matching current query and pagination metadata")
|
383
|
+
schema do
|
384
|
+
key :name, :total
|
385
|
+
key :description, I18n.t('apicasso.total.description',
|
386
|
+
default: 'Total records contained in current collection, as if there was no pagination.')
|
387
|
+
key :required, true
|
388
|
+
key :type, :integer
|
389
|
+
end
|
390
|
+
schema do
|
391
|
+
key :name, :total_pages
|
392
|
+
key :description, I18n.t('apicasso.total_pages.description',
|
393
|
+
default: 'How many pages of data the current collection has.')
|
394
|
+
key :required, true
|
395
|
+
key :type, :integer
|
396
|
+
end
|
397
|
+
schema do
|
398
|
+
key :name, :last_page
|
399
|
+
key :description, I18n.t('apicasso.last_page.description',
|
400
|
+
default: 'An indication if current request is the last to paginate in the current collection')
|
401
|
+
key :required, true
|
402
|
+
key :type, :boolean
|
403
|
+
end
|
404
|
+
schema do
|
405
|
+
key :name, :previous_page
|
406
|
+
key :description, I18n.t('apicasso.previous_page.description',
|
407
|
+
default: "The link of the previous page for the current collection. It can be null if there isn't any")
|
408
|
+
key :required, false
|
409
|
+
key :type, :string
|
410
|
+
end
|
411
|
+
schema do
|
412
|
+
key :name, :next_page
|
413
|
+
key :description, I18n.t('apicasso.next_page.description',
|
414
|
+
default: "The link of the next page for the current collection. It can be null if there isn't any")
|
415
|
+
key :required, false
|
416
|
+
key :type, :string
|
417
|
+
end
|
418
|
+
schema do
|
419
|
+
key :name, :out_of_bounds
|
420
|
+
key :description, I18n.t('apicasso.out_of_bounds.description',
|
421
|
+
default: 'An indication if current request is out of pagination bounds for the current collection')
|
422
|
+
key :required, true
|
423
|
+
key :type, :boolean
|
424
|
+
end
|
425
|
+
schema do
|
426
|
+
key :name, :offset
|
427
|
+
key :description, I18n.t('apicasso.offset.description',
|
428
|
+
default: 'How many records were offsetted from the collection to render the current page')
|
429
|
+
key :required, true
|
430
|
+
key :type, :integer
|
431
|
+
end
|
432
|
+
schema do
|
433
|
+
key :name, :entries
|
434
|
+
key :description, I18n.t('apicasso.entries.description',
|
435
|
+
default: 'The records collection in the current pagination scope.')
|
436
|
+
key :required, true
|
437
|
+
key :type, :array
|
438
|
+
items do
|
439
|
+
key :'$ref', "#{inner_name}".to_sym
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
response :default do
|
444
|
+
key :description, I18n.t("activerecord.errors.models.#{inner_name.underscore}",
|
445
|
+
default: "Unexpected error in #{inner_name}")
|
446
|
+
schema do
|
447
|
+
key :'$ref', :ErrorModel
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
operation :options do
|
452
|
+
key :description, I18n.t("activerecord.models.#{inner_name.underscore}.schema.description",
|
453
|
+
default: "#{inner_name} metadata information.")
|
454
|
+
key :operationId, "schema#{inner_name.pluralize}"
|
455
|
+
key :produces, ['application/json']
|
456
|
+
key :tags, [inner_name.underscore]
|
457
|
+
response 200 do
|
458
|
+
key :description, I18n.t("activerecord.models.#{inner_name.underscore}.schema.response",
|
459
|
+
default: "#{inner_name} metadata as a json with field names as keys and field types as values.")
|
460
|
+
schema do
|
461
|
+
key :'$ref', "#{inner_name}".to_sym
|
462
|
+
end
|
463
|
+
end
|
464
|
+
response :default do
|
465
|
+
key :description, I18n.t("activerecord.errors.models.#{inner_name.underscore}",
|
466
|
+
default: "Unexpected error in #{inner_name}")
|
467
|
+
schema do
|
468
|
+
key :'$ref', :ErrorModel
|
469
|
+
end
|
470
|
+
end
|
448
471
|
end
|
449
472
|
end
|
450
473
|
end
|
@@ -453,20 +476,7 @@ module Apicasso
|
|
453
476
|
end
|
454
477
|
|
455
478
|
def index
|
456
|
-
render json: Swagger::Blocks.build_root_json(SWAGGERED_CLASSES)
|
457
|
-
end
|
458
|
-
|
459
|
-
private
|
460
|
-
|
461
|
-
def extract_klass_name(opts = {})
|
462
|
-
association = opts[:model].reflect_on_all_associations.select{ |ass| ass.name == opts[:association] }.first
|
463
|
-
association.class_name
|
464
|
-
end
|
465
|
-
|
466
|
-
def extract_klass(opts = {})
|
467
|
-
extract_klass_name(opts).constantize
|
468
|
-
rescue NameError
|
469
|
-
return false
|
479
|
+
render json: Swagger::Blocks.build_root_json(SWAGGERED_CLASSES).to_json
|
470
480
|
end
|
471
481
|
end
|
472
482
|
end
|