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
data/README.md CHANGED
@@ -26,11 +26,13 @@ These gems are:
26
26
  - [Installation](#installation)
27
27
  - [Usage](#usage)
28
28
  - [Initial Setup](#initial-setup)
29
+ - [Exposed API mode](#exposed-api-mode)
29
30
  - [Command options:](#command-options)
30
31
  - [`--authenticated-resources`](#--authenticated-resources)
31
- - [Version Creation](#version-creation)
32
- - [Controller Generation](#controller-generation)
33
- - [Command options:](#command-options-1)
32
+ - [Internal API mode](#internal-api-mode)
33
+ - [Version Creation (exposed mode only)](#version-creation-exposed-mode-only)
34
+ - [Controller Generation (exposed and internal modes)](#controller-generation-exposed-and-internal-modes)
35
+ - [Command options (valid for internal and exposed modes):](#command-options-valid-for-internal-and-exposed-modes)
34
36
  - [`--attributes`](#--attributes)
35
37
  - [`--controller-actions`](#--controller-actions)
36
38
  - [`--version-number`](#--version-number)
@@ -43,6 +45,7 @@ These gems are:
43
45
  - [The `Api::Error` concern](#the-apierror-concern)
44
46
  - [The `Api::Deprecated` concern](#the-apideprecated-concern)
45
47
  - [The `ApiResponder`](#the-apiresponder)
48
+ - [The `PowerApi::ApplicationHelper#serialize_resource` helper method](#the-powerapiapplicationhelperserialize_resource-helper-method)
46
49
  - [Testing](#testing)
47
50
  - [Publishing](#publishing)
48
51
  - [Contributing](#contributing)
@@ -88,30 +91,13 @@ After doing this you will get:
88
91
  class Api::BaseController < PowerApi::BaseController
89
92
  end
90
93
  ```
91
- Here you should include everything common to all your API versions. It is usually empty because most of the configuration comes in the `PowerApi::BaseController` that es inside the gem.
92
-
93
- - A base controller for the first version of your API under `/your_api/app/controllers/api/v1/base_controller.rb`
94
- ```ruby
95
- class Api::V1::BaseController < Api::BaseController
96
- before_action do
97
- self.namespace_for_serializer = ::Api::V1
98
- end
99
- end
100
- ```
101
- Everything related to version 1 of your API must be included here.
94
+ Here you should include everything common to all your APIs. It is usually empty because most of the configuration comes in the `PowerApi::BaseController` that is inside the gem.
102
95
 
103
96
  - Some initializers:
104
97
  - `/your_api/config/initializers/active_model_serializers.rb`:
105
98
  ```ruby
106
- class ActiveModelSerializers::Adapter::JsonApi
107
- def self.default_key_transform
108
- :unaltered
109
- end
110
- end
111
-
112
- ActiveModelSerializers.config.adapter = :json_api
99
+ ActiveModelSerializers.config.adapter = :json
113
100
  ```
114
- Here we tell AMS that we will use the [json api](https://jsonapi.org/) format.
115
101
 
116
102
  - `/your_api/config/initializers/api_pagination.rb`:
117
103
  ```ruby
@@ -123,6 +109,30 @@ After doing this you will get:
123
109
  ```
124
110
  We use what comes by default and kaminari as pager.
125
111
 
112
+ After running the installer you must choose an API mode.
113
+ ### Exposed API mode
114
+
115
+ Use this mode if your API will be accessed by multiple clients or if your API is served somewhere other than your client application.
116
+
117
+ You must run the following command to have the exposed API mode configuration:
118
+
119
+ ```bash
120
+ rails generate power_api:exposed_api_config
121
+ ```
122
+
123
+ After doing this you will get:
124
+
125
+ - A base controller for the first version of your API under `/your_api/app/controllers/api/exposed/v1/base_controller.rb`
126
+ ```ruby
127
+ class Api::Exposed::V1::BaseController < Api::BaseController
128
+ before_action do
129
+ self.namespace_for_serializer = ::Api::V1
130
+ end
131
+ end
132
+ ```
133
+ Everything related to version 1 of your API must be included here.
134
+
135
+ - Some initializers:
126
136
  - `/your_api/config/initializers/rswag-api.rb`:
127
137
  ```ruby
128
138
  Rswag::Api.configure do |c|
@@ -196,7 +206,7 @@ After doing this you will get:
196
206
  }
197
207
  end
198
208
  ```
199
- - An empty directory indicating where you should put your serializers for the first version: `/your_api/app/serializers/api/v1/.gitkeep`
209
+ - An empty directory indicating where you should put your serializers for the first version: `/your_api/app/serializers/api/exposed/v1/.gitkeep`
200
210
  - An empty directory indicating where you should put your API tests: `/your_api/spec/integration/.gitkeep`
201
211
  - An empty directory indicating where you should put your swagger schemas `/your_api/spec/swagger/v1/schemas/.gitkeep`
202
212
 
@@ -225,7 +235,39 @@ Running the above code will generate, in addition to everything described in the
225
235
  ```
226
236
  - The migration `/your_api/db/migrate/20200228173608_add_authentication_token_to_users.rb` to add the `authentication_token` to your users table.
227
237
 
228
- ### Version Creation
238
+ ### Internal API mode
239
+
240
+ Use this mode if your API and your client app will be served on the same place.
241
+
242
+ You must run the following command to have the internal API mode configuration:
243
+
244
+ ```bash
245
+ rails generate power_api:internal_api_config
246
+ ```
247
+
248
+ After doing this you will get:
249
+
250
+ - A base controller for your internal API under `/your_api/app/controllers/api/internal/base_controller.rb`
251
+ ```ruby
252
+ class Api::Internal::BaseController < Api::BaseController
253
+ before_action do
254
+ self.namespace_for_serializer = ::Api::Internal
255
+ end
256
+ end
257
+ ```
258
+ Anything shared by the internal API controllers should go here.
259
+
260
+ - A modified `/your_api/config/routes.rb` file:
261
+ ```ruby
262
+ namespace :api, defaults: { format: :json } do
263
+ namespace :internal do
264
+ end
265
+ end
266
+ ```
267
+
268
+ - An empty directory indicating where you should put your serializers: `/your_api/app/serializers/api/internal/.gitkeep`
269
+
270
+ ### Version Creation (exposed mode only)
229
271
 
230
272
  To add a new version you must run the following command:
231
273
  ```bash
@@ -238,7 +280,7 @@ rails g power_api:version 2
238
280
 
239
281
  Doing this will add the same thing that was added for version one in the initial setup but this time for the number version provided as parameter.
240
282
 
241
- ### Controller Generation
283
+ ### Controller Generation (exposed and internal modes)
242
284
 
243
285
  To add a controller you must run the following command:
244
286
  ```bash
@@ -268,18 +310,29 @@ end
268
310
  after doing this you will get:
269
311
 
270
312
  - A modified `/your_api/config/routes.rb` file with the new resource:
271
- ```ruby
272
- Rails.application.routes.draw do
273
- scope path: '/api' do
274
- api_version(module: 'Api::V1', path: { value: 'v1' }, defaults: { format: 'json' }) do
275
- resources :blogs
313
+ - Exposed mode:
314
+ ```ruby
315
+ Rails.application.routes.draw do
316
+ scope path: '/api' do
317
+ api_version(module: 'Api::V1', path: { value: 'v1' }, defaults: { format: 'json' }) do
318
+ resources :blogs
319
+ end
276
320
  end
277
321
  end
278
- end
279
- ```
280
- - A controller under `/your_api/app/controllers/api/v1/blogs_controller.rb`
322
+ ```
323
+ - Internal mode:
324
+ ```ruby
325
+ Rails.application.routes.draw do
326
+ namespace :api, defaults: { format: :json } do
327
+ namespace :internal do
328
+ resources :blogs
329
+ end
330
+ end
331
+ end
332
+ ```
333
+ - A controller under `/your_api/app/controllers/api/exposed/v1/blogs_controller.rb`
281
334
  ```ruby
282
- class Api::V1::BlogsController < Api::V1::BaseController
335
+ class Api::Exposed::V1::BlogsController < Api::Exposed::V1::BaseController
283
336
  def index
284
337
  respond_with Blog.all
285
338
  end
@@ -308,18 +361,22 @@ after doing this you will get:
308
361
 
309
362
  def blog_params
310
363
  params.require(:blog).permit(
364
+ :id,
311
365
  :title,
312
366
  :body,
313
367
  )
314
368
  end
315
369
  end
316
370
  ```
317
- - A serializer under `/your_api/app/serializers/api/v1/blog_serializer.rb`
371
+ > With internal mode the file path will be: `/your_api/app/controllers/api/internal/blogs_controller.rb` and the class name: `Api::Internal::BlogsController`
372
+
373
+ - A serializer under `/your_api/app/serializers/api/exposed/v1/blog_serializer.rb`
318
374
  ```ruby
319
- class Api::V1::BlogSerializer < ActiveModel::Serializer
375
+ class Api::Exposed::V1::BlogSerializer < ActiveModel::Serializer
320
376
  type :blog
321
377
 
322
378
  attributes(
379
+ :id,
323
380
  :title,
324
381
  :body,
325
382
  :created_at,
@@ -327,7 +384,10 @@ after doing this you will get:
327
384
  )
328
385
  end
329
386
  ```
330
- - A spec file under `/your_api/spec/integration/api/v1/blogs_spec.rb`
387
+ > With internal mode the file path will be: `/your_api/app/serializers/api/internal/blog_serializer.rb` and the class name: `Api::Internal::BlogSerializer`
388
+
389
+ - A spec file under `/your_api/spec/integration/api/exposed/v1/blogs_spec.rb`
390
+ - Exposed mode:
331
391
  ```ruby
332
392
  require 'swagger_helper'
333
393
 
@@ -346,7 +406,7 @@ after doing this you will get:
346
406
  schema('$ref' => '#/definitions/blogs_collection')
347
407
 
348
408
  run_test! do |response|
349
- expect(JSON.parse(response.body)['data'].count).to eq(expected_collection_count)
409
+ expect(JSON.parse(response.body)['blogs'].count).to eq(expected_collection_count)
350
410
  end
351
411
  end
352
412
  end
@@ -357,7 +417,7 @@ after doing this you will get:
357
417
  produces 'application/json'
358
418
  parameter(name: :blog, in: :body)
359
419
 
360
- response '201', 'blog creaed' do
420
+ response '201', 'blog created' do
361
421
  let(:blog) do
362
422
  {
363
423
  title: 'Some title',
@@ -367,6 +427,16 @@ after doing this you will get:
367
427
 
368
428
  run_test!
369
429
  end
430
+
431
+ response '400', 'invalid attributes' do
432
+ let(:blog) do
433
+ {
434
+ title: nil
435
+ }
436
+ end
437
+
438
+ run_test!
439
+ end
370
440
  end
371
441
  end
372
442
 
@@ -407,6 +477,16 @@ after doing this you will get:
407
477
 
408
478
  run_test!
409
479
  end
480
+
481
+ response '400', 'invalid attributes' do
482
+ let(:blog) do
483
+ {
484
+ title: nil
485
+ }
486
+ end
487
+
488
+ run_test!
489
+ end
410
490
  end
411
491
 
412
492
  delete 'Deletes Blog' do
@@ -425,57 +505,203 @@ after doing this you will get:
425
505
  end
426
506
  end
427
507
  end
508
+
428
509
  ```
429
- - A swagger schema definition under `/your_api/spec/swagger/v1/schemas/blog_schema.rb`
510
+ - Internal mode:
511
+ ```ruby
512
+ require 'rails_helper'
513
+
514
+ describe 'Api::Internal::BlogsControllers', type: :request do
515
+ describe 'GET /index' do
516
+ let!(:blogs) { create_list(:blog, 5) }
517
+ let(:collection) { JSON.parse(response.body)['blogs'] }
518
+ let(:params) { {} }
519
+
520
+ def perform
521
+ get '/api/internal/blogs', params: params
522
+ end
523
+
524
+ before do
525
+ perform
526
+ end
527
+
528
+ it { expect(collection.count).to eq(5) }
529
+ it { expect(response.status).to eq(200) }
530
+ end
531
+
532
+ describe 'POST /create' do
533
+ let(:params) do
534
+ {
535
+ blog: {
536
+ title: 'Some title'
537
+ }
538
+ }
539
+ end
540
+
541
+ let(:attributes) do
542
+ JSON.parse(response.body)['blog'].symbolize_keys
543
+ end
544
+
545
+ def perform
546
+ post '/api/internal/blogs', params: params
547
+ end
548
+
549
+ before do
550
+ perform
551
+ end
552
+
553
+ it { expect(attributes).to include(params[:blog]) }
554
+ it { expect(response.status).to eq(201) }
555
+
556
+ context 'with invalid attributes' do
557
+ let(:params) do
558
+ {
559
+ blog: {
560
+ title: nil
561
+ }
562
+ }
563
+ end
564
+
565
+ it { expect(response.status).to eq(400) }
566
+ end
567
+ end
568
+
569
+ describe 'GET /show' do
570
+ let(:blog) { create(:blog) }
571
+ let(:blog_id) { blog.id.to_s }
572
+
573
+ let(:attributes) do
574
+ JSON.parse(response.body)['blog'].symbolize_keys
575
+ end
576
+
577
+ def perform
578
+ get '/api/internal/blogs/' + blog_id
579
+ end
580
+
581
+ before do
582
+ perform
583
+ end
584
+
585
+ it { expect(response.status).to eq(200) }
586
+
587
+ context 'with resource not found' do
588
+ let(:blog_id) { '666' }
589
+
590
+ it { expect(response.status).to eq(404) }
591
+ end
592
+ end
593
+
594
+ describe 'PUT /update' do
595
+ let(:blog) { create(:blog) }
596
+ let(:blog_id) { blog.id.to_s }
597
+
598
+ let(:params) do
599
+ {
600
+ blog: {
601
+ title: 'Some title'
602
+ }
603
+ }
604
+ end
605
+
606
+ let(:attributes) do
607
+ JSON.parse(response.body)['blog'].symbolize_keys
608
+ end
609
+
610
+ def perform
611
+ put '/api/internal/blogs/' + blog_id, params: params
612
+ end
613
+
614
+ before do
615
+ perform
616
+ end
617
+
618
+ it { expect(attributes).to include(params[:blog]) }
619
+ it { expect(response.status).to eq(200) }
620
+
621
+ context 'with invalid attributes' do
622
+ let(:params) do
623
+ {
624
+ blog: {
625
+ title: nil
626
+ }
627
+ }
628
+ end
629
+
630
+ it { expect(response.status).to eq(400) }
631
+ end
632
+
633
+ context 'with resource not found' do
634
+ let(:blog_id) { '666' }
635
+
636
+ it { expect(response.status).to eq(404) }
637
+ end
638
+ end
639
+
640
+ describe 'DELETE /destroy' do
641
+ let(:blog) { create(:blog) }
642
+ let(:blog_id) { blog.id.to_s }
643
+
644
+ def perform
645
+ get '/api/internal/blogs/' + blog_id
646
+ end
647
+
648
+ before do
649
+ perform
650
+ end
651
+
652
+ it { expect(response.status).to eq(200) }
653
+
654
+ context 'with resource not found' do
655
+ let(:blog_id) { '666' }
656
+
657
+ it { expect(response.status).to eq(404) }
658
+ end
659
+ end
660
+ end
661
+
662
+ ```
663
+ - A swagger schema definition under `/your_api/spec/swagger/v1/schemas/blog_schema.rb` (only for exposed mode)
430
664
  ```ruby
431
665
  BLOG_SCHEMA = {
432
666
  type: :object,
433
667
  properties: {
434
- id: { type: :string, example: '1' },
435
- type: { type: :string, example: 'blog' },
436
- attributes: {
437
- type: :object,
438
- properties: {
439
- title: { type: :string, example: 'Some title', 'x-nullable': true },
440
- body: { type: :string, example: 'Some body', 'x-nullable': true },
441
- created_at: { type: :string, example: '1984-06-04 09:00', 'x-nullable': true },
442
- updated_at: { type: :string, example: '1984-06-04 09:00', 'x-nullable': true }
443
- },
444
- required: [
445
- ]
446
- }
668
+ id: { type: :integer, example: 666 },
669
+ title: { type: :string, example: 'Some title' },
670
+ body: { type: :string, example: 'Some body' },
671
+ created_at: { type: :string, example: '1984-06-04 09:00', 'x-nullable': true },
672
+ updated_at: { type: :string, example: '1984-06-04 09:00', 'x-nullable': true },
673
+ portfolio_id: { type: :integer, example: 666, 'x-nullable': true }
447
674
  },
448
675
  required: [
449
- :id,
450
- :type,
451
- :attributes
676
+ :title,
677
+ :body
452
678
  ]
453
679
  }
454
680
 
455
681
  BLOGS_COLLECTION_SCHEMA = {
456
682
  type: "object",
457
683
  properties: {
458
- data: {
684
+ blogs: {
459
685
  type: "array",
460
686
  items: { "$ref" => "#/definitions/blog" }
461
687
  }
462
688
  },
463
689
  required: [
464
- :data
690
+ :blogs
465
691
  ]
466
692
  }
467
693
 
468
694
  BLOG_RESOURCE_SCHEMA = {
469
695
  type: "object",
470
696
  properties: {
471
- data: { "$ref" => "#/definitions/blog" }
697
+ blog: { "$ref" => "#/definitions/blog" }
472
698
  },
473
699
  required: [
474
- :data
700
+ :blog
475
701
  ]
476
702
  }
477
703
  ```
478
- - An edited version of `your_api/api_example/spec/swagger/v1/definition.rb` with the schema definitions for the `Blog` resource.
704
+ - An edited version of `your_api/api_example/spec/swagger/v1/definition.rb` with the schema definitions for the `Blog` resource. (only for exposed mode)
479
705
  ```ruby
480
706
  API_V1 = {
481
707
  swagger: '2.0',
@@ -492,7 +718,7 @@ after doing this you will get:
492
718
  }
493
719
  ```
494
720
 
495
- #### Command options:
721
+ #### Command options (valid for internal and exposed modes):
496
722
 
497
723
  ##### `--attributes`
498
724
 
@@ -504,9 +730,9 @@ rails g power_api:controller blog --attributes=title
504
730
 
505
731
  When you do this, you will see permited_params, serializers, swagger definitions, etc. showing only the selected attributes
506
732
 
507
- For example, the serializer under `/your_api/app/serializers/api/v1/blog_serializer.rb` will show:
733
+ For example, the serializer under `/your_api/app/serializers/api/exposed/v1/blog_serializer.rb` will show:
508
734
  ```ruby
509
- class Api::V1::BlogSerializer < ActiveModel::Serializer
735
+ class Api::Exposed::V1::BlogSerializer < ActiveModel::Serializer
510
736
  type :blog
511
737
 
512
738
  attributes(
@@ -528,7 +754,7 @@ When you do this, you will see that only relevant code is generated in controlle
528
754
  For example, the controller would only include the `show` and `destroy` actions and wouldn't include the `blog_params` method:
529
755
 
530
756
  ```ruby
531
- class Api::V1::BlogSerializer < Api::V1::BaseController
757
+ class Api::Exposed::V1::BlogController < Api::Exposed::V1::BaseController
532
758
  def show
533
759
  respond_with blog
534
760
  end
@@ -553,6 +779,8 @@ Use this option if you want to decide which version the new controller will belo
553
779
  rails g power_api:controller blog --version-number=2
554
780
  ```
555
781
 
782
+ > Important! When working with exposed api you should always specify the version, otherwise the controller will be generated for the internal api mode.
783
+
556
784
  ##### `--use-paginator`
557
785
 
558
786
  Use this option if you want to paginate the index endpoint collection.
@@ -561,10 +789,10 @@ Use this option if you want to paginate the index endpoint collection.
561
789
  rails g power_api:controller blog --use-paginator
562
790
  ```
563
791
 
564
- The controller under `/your_api/app/controllers/api/v1/blogs_controller.rb` will be modified to use the paginator like this:
792
+ The controller under `/your_api/app/controllers/api/exposed/v1/blogs_controller.rb` will be modified to use the paginator like this:
565
793
 
566
794
  ```ruby
567
- class Api::V1::BlogsController < Api::V1::BaseController
795
+ class Api::Exposed::V1::BlogsController < Api::Exposed::V1::BaseController
568
796
  def index
569
797
  respond_with paginate(Blog.all)
570
798
  end
@@ -585,10 +813,10 @@ Use this option if you want to filter your index endpoint collection with [Ransa
585
813
  rails g power_api:controller blog --allow-filters
586
814
  ```
587
815
 
588
- The controller under `/your_api/app/controllers/api/v1/blogs_controller.rb` will be modified like this:
816
+ The controller under `/your_api/app/controllers/api/exposed/v1/blogs_controller.rb` will be modified like this:
589
817
 
590
818
  ```ruby
591
- class Api::V1::BlogsController < Api::V1::BaseController
819
+ class Api::Exposed::V1::BlogsController < Api::Exposed::V1::BaseController
592
820
  def index
593
821
  respond_with filtered_collection(Blog.all)
594
822
  end
@@ -625,13 +853,15 @@ rails g power_api:controller blog --authenticate-with=user
625
853
  When you do this your controller will have the following line:
626
854
 
627
855
  ```ruby
628
- class Api::V1::BlogsController < Api::V1::BaseController
856
+ class Api::Exposed::V1::BlogsController < Api::Exposed::V1::BaseController
629
857
  acts_as_token_authentication_handler_for User, fallback: :exception
630
858
 
631
859
  # mode code...
632
860
  end
633
861
  ```
634
862
 
863
+ > With internal mode a `before_action :authenticate_user!` statement will be added instead of `acts_as_token_authentication_handler_for` in order to work with devise gem directly.
864
+
635
865
  In addition, the specs under `/your_api/spec/integration/api/v1/blogs_spec.rb` will add tests related with authorization.
636
866
 
637
867
  ```ruby
@@ -653,7 +883,7 @@ rails g power_api:controller blog --authenticate-with=user --owned-by-authentica
653
883
  The controller will look like this:
654
884
 
655
885
  ```ruby
656
- class Api::V1::BlogsController < Api::V1::BaseController
886
+ class Api::Exposed::V1::BlogsController < Api::Exposed::V1::BaseController
657
887
  acts_as_token_authentication_handler_for User, fallback: :exception
658
888
 
659
889
  def index
@@ -688,6 +918,7 @@ class Api::V1::BlogsController < Api::V1::BaseController
688
918
 
689
919
  def blog_params
690
920
  params.require(:blog).permit(
921
+ :id,
691
922
  :title,
692
923
  :body
693
924
  )
@@ -731,9 +962,9 @@ rails g power_api:controller comment --attributes=body --parent-resource=blog
731
962
 
732
963
  Running the previous code we will get:
733
964
 
734
- - The controller under `/your_api/app/controllers/api/v1/comments_controller.rb`:
965
+ - The controller under `/your_api/app/controllers/api/exposed/v1/comments_controller.rb`:
735
966
  ```ruby
736
- class Api::V1::CommentsController < Api::V1::BaseController
967
+ class Api::Exposed::V1::CommentsController < Api::Exposed::V1::BaseController
737
968
  def index
738
969
  respond_with comments
739
970
  end
@@ -770,6 +1001,7 @@ Running the previous code we will get:
770
1001
 
771
1002
  def comment_params
772
1003
  params.require(:comment).permit(
1004
+ :id,
773
1005
  :body
774
1006
  )
775
1007
  end
@@ -868,7 +1100,7 @@ This module is useful when you want to mark endpoints as deprecated.
868
1100
  For example, if you have the following controller:
869
1101
 
870
1102
  ```ruby
871
- class Api::V1::CommentsController < Api::V1::BaseController
1103
+ class Api::Exposed::V1::CommentsController < Api::Exposed::V1::BaseController
872
1104
  deprecate :index
873
1105
 
874
1106
  def index
@@ -905,6 +1137,28 @@ end
905
1137
 
906
1138
  As you can see, this simple [Responder](https://github.com/heartcombo/responders) handles the API response based on the HTTP verbs.
907
1139
 
1140
+ ### The `PowerApi::ApplicationHelper#serialize_resource` helper method
1141
+
1142
+ This helper method is useful if you want to serialize ActiveRecord resources to use in your views. For example, you can do:
1143
+
1144
+ ```
1145
+ <pre>
1146
+ <%= serialize_resource(@resource, @options) %>
1147
+ </pre>
1148
+ ```
1149
+
1150
+ To get:
1151
+
1152
+ ```
1153
+ {"id":1,"title":"lean","body":"bla","createdAt":"2022-01-08T18:15:46.624Z","updatedAt":"2022-01-08T18:15:46.624Z","portfolioId":null}
1154
+ ```
1155
+
1156
+ The `@resource` parameter must be an ActiveRecord instance (`ApplicationRecord`) or collection (`ActiveRecord_Relation`).
1157
+
1158
+ The `@options` parameter must be a `Hash` and can contain the options you commonly use with Active Model Serializer gem (`fields`, `transform_key`, etc.) and some others:
1159
+ - `include_root`: to get something like: `{"id":1,"title":"lean"}` or `{"blog": {"id":1,"title":"lean"}}`.
1160
+ - `output_format`: can be `:hash` or `:json`.
1161
+
908
1162
  ## Testing
909
1163
 
910
1164
  To run the specs you need to execute, **in the root path of the gem**, the following command:
@@ -944,4 +1198,4 @@ Power API is maintained by [platanus](http://platan.us).
944
1198
 
945
1199
  ## License
946
1200
 
947
- Power API is © 2019 platanus, spa. It is free software and may be redistributed under the terms specified in the LICENSE file.
1201
+ Power API is © 2022 platanus, spa. It is free software and may be redistributed under the terms specified in the LICENSE file.