power_api 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +93 -90
  5. data/README.md +329 -75
  6. data/app/helpers/power_api/application_helper.rb +57 -0
  7. data/bin/clean_test_app +2 -0
  8. data/lib/generators/power_api/controller/controller_generator.rb +27 -15
  9. data/lib/generators/power_api/exposed_api_config/USAGE +5 -0
  10. data/lib/generators/power_api/exposed_api_config/exposed_api_config_generator.rb +58 -0
  11. data/lib/generators/power_api/install/install_generator.rb +2 -44
  12. data/lib/generators/power_api/internal_api_config/USAGE +5 -0
  13. data/lib/generators/power_api/internal_api_config/internal_api_config_generator.rb +31 -0
  14. data/lib/generators/power_api/version/version_generator.rb +2 -2
  15. data/lib/power_api/engine.rb +8 -1
  16. data/lib/power_api/errors.rb +2 -0
  17. data/lib/power_api/generator_helper/active_record_resource.rb +10 -6
  18. data/lib/power_api/generator_helper/ams_helper.rb +5 -11
  19. data/lib/power_api/generator_helper/api_helper.rb +61 -0
  20. data/lib/power_api/generator_helper/controller_helper.rb +45 -15
  21. data/lib/power_api/generator_helper/routes_helper.rb +22 -7
  22. data/lib/power_api/generator_helper/rspec_controller_helper.rb +306 -0
  23. data/lib/power_api/generator_helper/swagger_helper.rb +14 -24
  24. data/lib/power_api/generator_helpers.rb +2 -1
  25. data/lib/power_api/version.rb +1 -1
  26. data/spec/dummy/app/controllers/api/base_controller.rb +2 -0
  27. data/spec/dummy/app/controllers/api/internal/base_controller.rb +5 -0
  28. data/spec/dummy/app/controllers/api/internal/blogs_controller.rb +36 -0
  29. data/spec/dummy/app/serializers/api/internal/blog_serializer.rb +12 -0
  30. data/spec/dummy/config/initializers/active_model_serializers.rb +1 -0
  31. data/spec/dummy/config/initializers/api_pagination.rb +32 -0
  32. data/spec/dummy/config/routes.rb +2 -7
  33. data/spec/dummy/spec/helpers/power_api/application_helper_spec.rb +171 -0
  34. data/spec/dummy/spec/lib/power_api/generator_helper/ams_helper_spec.rb +50 -12
  35. data/spec/dummy/spec/lib/power_api/generator_helper/api_helper_spec.rb +115 -0
  36. data/spec/dummy/spec/lib/power_api/generator_helper/controller_helper_spec.rb +126 -34
  37. data/spec/dummy/spec/lib/power_api/generator_helper/routes_helper_spec.rb +29 -5
  38. data/spec/dummy/spec/lib/power_api/generator_helper/rspec_controller_helper_spec.rb +559 -0
  39. data/spec/dummy/spec/lib/power_api/generator_helper/swagger_helper_spec.rb +10 -20
  40. data/spec/dummy/spec/support/shared_examples/active_record_resource_atrributes.rb +22 -3
  41. metadata +27 -5
  42. data/lib/power_api/generator_helper/version_helper.rb +0 -16
  43. data/spec/dummy/spec/lib/power_api/generator_helper/version_helper_spec.rb +0 -55
@@ -9,14 +9,21 @@ RSpec.describe PowerApi::GeneratorHelper::RoutesHelper, type: :generator do
9
9
  it { expect(perform).to eq(expected_path) }
10
10
  end
11
11
 
12
- describe "#api_version_routes_line_regex" do
13
- let(:expected_regex) { /Api::V1[^\n]*/ }
12
+ describe "#api_current_route_namespace_line_regex" do
13
+ let(:expected_regex) { /Api::Exposed::V1[^\n]*/ }
14
14
 
15
15
  def perform
16
- generators_helper.api_version_routes_line_regex
16
+ generators_helper.api_current_route_namespace_line_regex
17
17
  end
18
18
 
19
19
  it { expect(perform).to eq(expected_regex) }
20
+
21
+ context "without version" do
22
+ let(:version_number) { "" }
23
+ let(:expected_regex) { /namespace :internal[^\n]*/ }
24
+
25
+ it { expect(perform).to eq(expected_regex) }
26
+ end
20
27
  end
21
28
 
22
29
  describe "#parent_resource_routes_line_regex" do
@@ -87,7 +94,7 @@ RSpec.describe PowerApi::GeneratorHelper::RoutesHelper, type: :generator do
87
94
  let(:expected_tpl) do
88
95
  <<~ROUTE
89
96
  scope path: '/api' do
90
- api_version(module: 'Api::V1', path: { value: 'v1' }, defaults: { format: 'json' }) do
97
+ api_version(module: 'Api::Exposed::V1', path: { value: 'v1' }, defaults: { format: 'json' }) do
91
98
  end
92
99
  end
93
100
  ROUTE
@@ -104,7 +111,7 @@ RSpec.describe PowerApi::GeneratorHelper::RoutesHelper, type: :generator do
104
111
 
105
112
  let(:expected_tpl) do
106
113
  <<~ROUTE
107
- api_version(module: 'Api::V2', path: { value: 'v2' }, defaults: { format: 'json' }) do
114
+ api_version(module: 'Api::Exposed::V2', path: { value: 'v2' }, defaults: { format: 'json' }) do
108
115
  end
109
116
  ROUTE
110
117
  end
@@ -113,6 +120,23 @@ RSpec.describe PowerApi::GeneratorHelper::RoutesHelper, type: :generator do
113
120
  end
114
121
  end
115
122
 
123
+ describe "#internal_route_tpl" do
124
+ let(:expected_tpl) do
125
+ <<~ROUTE
126
+ namespace :api, defaults: { format: :json } do
127
+ namespace :internal do
128
+ end
129
+ end
130
+ ROUTE
131
+ end
132
+
133
+ def perform
134
+ generators_helper.internal_route_tpl
135
+ end
136
+
137
+ it { expect(perform).to eq(expected_tpl) }
138
+ end
139
+
116
140
  describe "#parent_route_exist?" do
117
141
  let(:parent_resource_name) { "user" }
118
142
  let(:line) { nil }
@@ -0,0 +1,559 @@
1
+ describe PowerApi::GeneratorHelper::RspecControllerHelper, type: :generator do
2
+ describe "#resource_spec_path" do
3
+ let(:expected_path) { "spec/requests/api/exposed/v1/blogs_spec.rb" }
4
+
5
+ def perform
6
+ generators_helper.resource_spec_path
7
+ end
8
+
9
+ it { expect(perform).to eq(expected_path) }
10
+
11
+ context "when nil version" do
12
+ let(:version_number) { nil }
13
+ let(:expected_path) { "spec/requests/api/internal/blogs_spec.rb" }
14
+
15
+ it { expect(perform).to eq(expected_path) }
16
+ end
17
+ end
18
+
19
+ describe "#resource_spec_tpl" do
20
+ let(:template) do
21
+ <<~SPEC
22
+ require 'rails_helper'
23
+
24
+ RSpec.describe 'Api::Exposed::V1::BlogsControllers', type: :request do
25
+ describe 'GET /index' do
26
+ let!(:blogs) { create_list(:blog, 5) }
27
+ let(:collection) { JSON.parse(response.body)['blogs'] }
28
+ let(:params) { {} }
29
+
30
+ def perform
31
+ get '/api/v1/blogs', params: params
32
+ end
33
+
34
+ before do
35
+ perform
36
+ end
37
+
38
+ it { expect(collection.count).to eq(5) }
39
+ it { expect(response.status).to eq(200) }
40
+ end
41
+
42
+ describe 'POST /create' do
43
+ let(:params) do
44
+ {
45
+ blog: {
46
+ title: 'Some title',
47
+ body: 'Some body'
48
+ }
49
+ }
50
+ end
51
+
52
+ let(:attributes) do
53
+ JSON.parse(response.body)['blog'].symbolize_keys
54
+ end
55
+ def perform
56
+ post '/api/v1/blogs', params: params
57
+ end
58
+
59
+ before do
60
+ perform
61
+ end
62
+
63
+ it { expect(attributes).to include(params[:blog]) }
64
+ it { expect(response.status).to eq(201) }
65
+ context 'with invalid attributes' do
66
+ let(:params) do
67
+ {
68
+ blog: {
69
+ title: nil}
70
+ }
71
+ end
72
+
73
+ it { expect(response.status).to eq(400) }
74
+ end
75
+
76
+ end
77
+
78
+ describe 'GET /show' do
79
+ let(:blog) { create(:blog) }
80
+ let(:blog_id) { blog.id.to_s }
81
+
82
+ let(:attributes) do
83
+ JSON.parse(response.body)['blog'].symbolize_keys
84
+ end
85
+ def perform
86
+ get '/api/v1/blogs/' + blog_id
87
+ end
88
+
89
+ before do
90
+ perform
91
+ end
92
+
93
+ it { expect(response.status).to eq(200) }
94
+ context 'with resource not found' do
95
+ let(:blog_id) { '666' }
96
+ it { expect(response.status).to eq(404) }
97
+ end
98
+ end
99
+
100
+ describe 'PUT /update' do
101
+ let(:blog) { create(:blog) }
102
+ let(:blog_id) { blog.id.to_s }
103
+
104
+ let(:params) do
105
+ {
106
+ blog: {
107
+ title: 'Some title',
108
+ body: 'Some body'
109
+ }
110
+ }
111
+ end
112
+
113
+ let(:attributes) do
114
+ JSON.parse(response.body)['blog'].symbolize_keys
115
+ end
116
+ def perform
117
+ put '/api/v1/blogs/' + blog_id, params: params
118
+ end
119
+
120
+ before do
121
+ perform
122
+ end
123
+
124
+ it { expect(attributes).to include(params[:blog]) }
125
+ it { expect(response.status).to eq(200) }
126
+ context 'with invalid attributes' do
127
+ let(:params) do
128
+ {
129
+ blog: {
130
+ title: nil}
131
+ }
132
+ end
133
+
134
+ it { expect(response.status).to eq(400) }
135
+ end
136
+
137
+ context 'with resource not found' do
138
+ let(:blog_id) { '666' }
139
+ it { expect(response.status).to eq(404) }
140
+ end
141
+ end
142
+
143
+ describe 'DELETE /destroy' do
144
+ let(:blog) { create(:blog) }
145
+ let(:blog_id) { blog.id.to_s }
146
+
147
+ def perform
148
+ get '/api/v1/blogs/' + blog_id
149
+ end
150
+
151
+ before do
152
+ perform
153
+ end
154
+
155
+ it { expect(response.status).to eq(200) }
156
+ context 'with resource not found' do
157
+ let(:blog_id) { '666' }
158
+ it { expect(response.status).to eq(404) }
159
+ end
160
+ end
161
+
162
+ end
163
+ SPEC
164
+ end
165
+
166
+ def perform
167
+ generators_helper.resource_spec_tpl
168
+ end
169
+
170
+ it { expect(perform).to eq(template) }
171
+
172
+ context "when nil version" do
173
+ let(:version_number) { nil }
174
+
175
+ it { expect(perform).to include("RSpec.describe 'Api::Internal::BlogsControllers'") }
176
+ it { expect(perform).to include("get '/api/internal/blogs', params: params") }
177
+ end
178
+
179
+ context "with authenticated_resource option" do
180
+ let(:authenticated_resource) { "user" }
181
+
182
+ let(:template) do
183
+ <<~SPEC
184
+ require 'rails_helper'
185
+
186
+ RSpec.describe 'Api::Exposed::V1::BlogsControllers', type: :request do
187
+ let(:user) { create(:user) }
188
+ describe 'GET /index' do
189
+ let!(:blogs) { create_list(:blog, 5) }
190
+ let(:collection) { JSON.parse(response.body)['blogs'] }
191
+ let(:params) { {} }
192
+
193
+ def perform
194
+ get '/api/v1/blogs', params: params
195
+ end
196
+
197
+ context 'with authorized user' do
198
+ before do
199
+ sign_in(user)
200
+ perform
201
+ end
202
+
203
+ it { expect(collection.count).to eq(5) }
204
+ it { expect(response.status).to eq(200) }
205
+ end
206
+
207
+ context 'with unauthenticated user' do
208
+ before { perform }
209
+
210
+ it { expect(response.status).to eq(401) }
211
+ end
212
+
213
+ end
214
+
215
+ describe 'POST /create' do
216
+ let(:params) do
217
+ {
218
+ blog: {
219
+ title: 'Some title',
220
+ body: 'Some body'
221
+ }
222
+ }
223
+ end
224
+
225
+ let(:attributes) do
226
+ JSON.parse(response.body)['blog'].symbolize_keys
227
+ end
228
+ def perform
229
+ post '/api/v1/blogs', params: params
230
+ end
231
+
232
+ context 'with authorized user' do
233
+ before do
234
+ sign_in(user)
235
+ perform
236
+ end
237
+
238
+ it { expect(attributes).to include(params[:blog]) }
239
+ it { expect(response.status).to eq(201) }
240
+ context 'with invalid attributes' do
241
+ let(:params) do
242
+ {
243
+ blog: {
244
+ title: nil}
245
+ }
246
+ end
247
+
248
+ it { expect(response.status).to eq(400) }
249
+ end
250
+
251
+ end
252
+
253
+ context 'with unauthenticated user' do
254
+ before { perform }
255
+
256
+ it { expect(response.status).to eq(401) }
257
+ end
258
+
259
+ end
260
+
261
+ describe 'GET /show' do
262
+ let(:blog) { create(:blog) }
263
+ let(:blog_id) { blog.id.to_s }
264
+
265
+ let(:attributes) do
266
+ JSON.parse(response.body)['blog'].symbolize_keys
267
+ end
268
+ def perform
269
+ get '/api/v1/blogs/' + blog_id
270
+ end
271
+
272
+ context 'with authorized user' do
273
+ before do
274
+ sign_in(user)
275
+ perform
276
+ end
277
+
278
+ it { expect(response.status).to eq(200) }
279
+ context 'with resource not found' do
280
+ let(:blog_id) { '666' }
281
+ it { expect(response.status).to eq(404) }
282
+ end
283
+ end
284
+
285
+ context 'with unauthenticated user' do
286
+ before { perform }
287
+
288
+ it { expect(response.status).to eq(401) }
289
+ end
290
+
291
+ end
292
+
293
+ describe 'PUT /update' do
294
+ let(:blog) { create(:blog) }
295
+ let(:blog_id) { blog.id.to_s }
296
+
297
+ let(:params) do
298
+ {
299
+ blog: {
300
+ title: 'Some title',
301
+ body: 'Some body'
302
+ }
303
+ }
304
+ end
305
+
306
+ let(:attributes) do
307
+ JSON.parse(response.body)['blog'].symbolize_keys
308
+ end
309
+ def perform
310
+ put '/api/v1/blogs/' + blog_id, params: params
311
+ end
312
+
313
+ context 'with authorized user' do
314
+ before do
315
+ sign_in(user)
316
+ perform
317
+ end
318
+
319
+ it { expect(attributes).to include(params[:blog]) }
320
+ it { expect(response.status).to eq(200) }
321
+ context 'with invalid attributes' do
322
+ let(:params) do
323
+ {
324
+ blog: {
325
+ title: nil}
326
+ }
327
+ end
328
+
329
+ it { expect(response.status).to eq(400) }
330
+ end
331
+
332
+ context 'with resource not found' do
333
+ let(:blog_id) { '666' }
334
+ it { expect(response.status).to eq(404) }
335
+ end
336
+ end
337
+
338
+ context 'with unauthenticated user' do
339
+ before { perform }
340
+
341
+ it { expect(response.status).to eq(401) }
342
+ end
343
+
344
+ end
345
+
346
+ describe 'DELETE /destroy' do
347
+ let(:blog) { create(:blog) }
348
+ let(:blog_id) { blog.id.to_s }
349
+
350
+ def perform
351
+ get '/api/v1/blogs/' + blog_id
352
+ end
353
+
354
+ context 'with authorized user' do
355
+ before do
356
+ sign_in(user)
357
+ perform
358
+ end
359
+
360
+ it { expect(response.status).to eq(200) }
361
+ context 'with resource not found' do
362
+ let(:blog_id) { '666' }
363
+ it { expect(response.status).to eq(404) }
364
+ end
365
+ end
366
+
367
+ context 'with unauthenticated user' do
368
+ before { perform }
369
+
370
+ it { expect(response.status).to eq(401) }
371
+ end
372
+
373
+ end
374
+
375
+ end
376
+ SPEC
377
+ end
378
+
379
+ it { expect(perform).to eq(template) }
380
+
381
+ context "with owned_by_authenticated_resource option" do
382
+ let(:authenticated_resource) { "user" }
383
+ let(:owned_by_authenticated_resource) { true }
384
+
385
+ it { expect(perform).to include("create_list(:blog, 5, user: user)") }
386
+ end
387
+ end
388
+
389
+ context "with parent_resource option" do
390
+ let(:parent_resource_name) { "portfolio" }
391
+
392
+ let(:template) do
393
+ <<~SPEC
394
+ require 'rails_helper'
395
+
396
+ RSpec.describe 'Api::Exposed::V1::BlogsControllers', type: :request do
397
+ let(:portfolio) { create(:portfolio) }
398
+ let(:portfolio_id) { portfolio.id }
399
+
400
+ describe 'GET /index' do
401
+ let!(:blogs) { create_list(:blog, 5, portfolio: portfolio) }
402
+ let(:collection) { JSON.parse(response.body)['blogs'] }
403
+ let(:params) { {} }
404
+
405
+ def perform
406
+ get '/api/v1/portfolios/' + portfolio.id.to_s + '/blogs', params: params
407
+ end
408
+
409
+ before do
410
+ perform
411
+ end
412
+
413
+ it { expect(collection.count).to eq(5) }
414
+ it { expect(response.status).to eq(200) }
415
+ end
416
+
417
+ describe 'POST /create' do
418
+ let(:params) do
419
+ {
420
+ blog: {
421
+ title: 'Some title',
422
+ body: 'Some body'
423
+ }
424
+ }
425
+ end
426
+
427
+ let(:attributes) do
428
+ JSON.parse(response.body)['blog'].symbolize_keys
429
+ end
430
+ def perform
431
+ post '/api/v1/portfolios/' + portfolio.id.to_s + '/blogs', params: params
432
+ end
433
+
434
+ before do
435
+ perform
436
+ end
437
+
438
+ it { expect(attributes).to include(params[:blog]) }
439
+ it { expect(response.status).to eq(201) }
440
+ context 'with invalid attributes' do
441
+ let(:params) do
442
+ {
443
+ blog: {
444
+ title: nil}
445
+ }
446
+ end
447
+
448
+ it { expect(response.status).to eq(400) }
449
+ end
450
+
451
+ end
452
+
453
+ describe 'GET /show' do
454
+ let(:blog) { create(:blog, portfolio: portfolio) }
455
+ let(:blog_id) { blog.id.to_s }
456
+
457
+ let(:attributes) do
458
+ JSON.parse(response.body)['blog'].symbolize_keys
459
+ end
460
+ def perform
461
+ get '/api/v1/blogs/' + blog_id
462
+ end
463
+
464
+ before do
465
+ perform
466
+ end
467
+
468
+ it { expect(response.status).to eq(200) }
469
+ context 'with resource not found' do
470
+ let(:blog_id) { '666' }
471
+ it { expect(response.status).to eq(404) }
472
+ end
473
+ end
474
+
475
+ describe 'PUT /update' do
476
+ let(:blog) { create(:blog, portfolio: portfolio) }
477
+ let(:blog_id) { blog.id.to_s }
478
+
479
+ let(:params) do
480
+ {
481
+ blog: {
482
+ title: 'Some title',
483
+ body: 'Some body'
484
+ }
485
+ }
486
+ end
487
+
488
+ let(:attributes) do
489
+ JSON.parse(response.body)['blog'].symbolize_keys
490
+ end
491
+ def perform
492
+ put '/api/v1/blogs/' + blog_id, params: params
493
+ end
494
+
495
+ before do
496
+ perform
497
+ end
498
+
499
+ it { expect(attributes).to include(params[:blog]) }
500
+ it { expect(response.status).to eq(200) }
501
+ context 'with invalid attributes' do
502
+ let(:params) do
503
+ {
504
+ blog: {
505
+ title: nil}
506
+ }
507
+ end
508
+
509
+ it { expect(response.status).to eq(400) }
510
+ end
511
+
512
+ context 'with resource not found' do
513
+ let(:blog_id) { '666' }
514
+ it { expect(response.status).to eq(404) }
515
+ end
516
+ end
517
+
518
+ describe 'DELETE /destroy' do
519
+ let(:blog) { create(:blog, portfolio: portfolio) }
520
+ let(:blog_id) { blog.id.to_s }
521
+
522
+ def perform
523
+ get '/api/v1/blogs/' + blog_id
524
+ end
525
+
526
+ before do
527
+ perform
528
+ end
529
+
530
+ it { expect(response.status).to eq(200) }
531
+ context 'with resource not found' do
532
+ let(:blog_id) { '666' }
533
+ it { expect(response.status).to eq(404) }
534
+ end
535
+ end
536
+
537
+ end
538
+ SPEC
539
+ end
540
+
541
+ it { expect(perform).to eq(template) }
542
+ end
543
+
544
+ context 'with only some actions (show and create)' do
545
+ let(:controller_actions) do
546
+ [
547
+ "show",
548
+ "create"
549
+ ]
550
+ end
551
+
552
+ it { expect(perform).to include("describe 'GET /show'") }
553
+ it { expect(perform).to include("describe 'POST /create'") }
554
+ it { expect(perform).not_to include("describe 'DELETE /destroy'") }
555
+ it { expect(perform).not_to include("describe 'PUT /update'") }
556
+ it { expect(perform).not_to include("describe 'GET /index'") }
557
+ end
558
+ end
559
+ end
@@ -1,4 +1,4 @@
1
- RSpec.describe PowerApi::GeneratorHelper::SwaggerHelper, type: :generator do
1
+ describe PowerApi::GeneratorHelper::SwaggerHelper, type: :generator do
2
2
  describe "#swagger_helper_path" do
3
3
  let(:expected_path) { "spec/swagger_helper.rb" }
4
4
 
@@ -206,50 +206,40 @@ RSpec.describe PowerApi::GeneratorHelper::SwaggerHelper, type: :generator do
206
206
  BLOG_SCHEMA = {
207
207
  type: :object,
208
208
  properties: {
209
- id: { type: :string, example: '1' },
210
- type: { type: :string, example: 'blog' },
211
- attributes: {
212
- type: :object,
213
- properties: {
209
+ id: { type: :integer, example: 666 },
214
210
  title: { type: :string, example: 'Some title' },
215
211
  body: { type: :string, example: 'Some body' },
216
212
  created_at: { type: :string, example: '1984-06-04 09:00', 'x-nullable': true },
217
213
  updated_at: { type: :string, example: '1984-06-04 09:00', 'x-nullable': true },
218
214
  portfolio_id: { type: :integer, example: 666, 'x-nullable': true }
219
- },
220
- required: [
221
- :title,
222
- :body
223
- ]
224
- }
225
215
  },
226
216
  required: [
227
- :id,
228
- :type,
229
- :attributes
217
+ :id,
218
+ :title,
219
+ :body
230
220
  ]
231
221
  }
232
222
 
233
223
  BLOGS_COLLECTION_SCHEMA = {
234
224
  type: "object",
235
225
  properties: {
236
- data: {
226
+ blogs: {
237
227
  type: "array",
238
228
  items: { "$ref" => "#/definitions/blog" }
239
229
  }
240
230
  },
241
231
  required: [
242
- :data
232
+ :blogs
243
233
  ]
244
234
  }
245
235
 
246
236
  BLOG_RESOURCE_SCHEMA = {
247
237
  type: "object",
248
238
  properties: {
249
- data: { "$ref" => "#/definitions/blog" }
239
+ blog: { "$ref" => "#/definitions/blog" }
250
240
  },
251
241
  required: [
252
- :data
242
+ :blog
253
243
  ]
254
244
  }
255
245
  SCHEMA
@@ -281,7 +271,7 @@ RSpec.describe PowerApi::GeneratorHelper::SwaggerHelper, type: :generator do
281
271
  schema('$ref' => '#/definitions/blogs_collection')
282
272
 
283
273
  run_test! do |response|
284
- expect(JSON.parse(response.body)['data'].count).to eq(expected_collection_count)
274
+ expect(JSON.parse(response.body)['blogs'].count).to eq(expected_collection_count)
285
275
  end
286
276
  end
287
277