rest-api-generator 0.2.0 → 0.3.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/Gemfile.lock +1 -1
- data/README.md +6 -338
- data/app/controllers/rest_api_generator/child_resource_controller.rb +7 -2
- data/app/controllers/rest_api_generator/resource_controller.rb +4 -2
- data/lib/rest_api_generator/controller_callbacks.rb +30 -0
- data/lib/rest_api_generator/version.rb +1 -1
- data/lib/rest_api_generator.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a42f65c1630afe3db2bc1acb7c66272b9703e61ac761d509b0561e6c9369d7df
|
4
|
+
data.tar.gz: 898e903b7b81efa687f272a18ec7179f42ac566da404b1f046002b74345c9f77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83e49d124a05cee3c742a69d5d2b1f798014e331c2a662a2bd7b0b19cb99ca45d66bdd290fa996e0c7e969d302fc9ecd49e9c69554836fe582d55adbb06f8f66
|
7
|
+
data.tar.gz: 14bd2117229d7cc2cb6b17371f7d0767720e3b6051ddcfc5fa6fb95aec438c29db25800ec5d44505284e4c56ba817e36666fa9118262228d5ab6086d740b0016
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
This gem helps you to build a Ruby on Rails REST API faster, using a scaffold-like generator that follows the best
|
4
4
|
practices.
|
5
5
|
|
6
|
+
## Get started
|
7
|
+
|
8
|
+
:zap: **Quick Start**: [docs](https://rest-api-generator.switchdreams.com.br/quick-start)\
|
9
|
+
:books: **Documentation**: [docs](https://rest-api-generator.switchdreams.com.br/)
|
10
|
+
|
6
11
|
## How it works?
|
7
12
|
|
8
13
|
The gems use vanilla Rails generators in combination with our templates to create all the resources needed to build a
|
@@ -27,6 +32,7 @@ Following [Switch Dreams's](https://www.switchdreams.com.br/]) coding practices,
|
|
27
32
|
- [Resource pagination](#pagination)
|
28
33
|
- [Resource serialization](#serialization)
|
29
34
|
- [Configurable](#configuration)
|
35
|
+
- [Callbacks](#callbacks)
|
30
36
|
|
31
37
|
## Next Features
|
32
38
|
|
@@ -34,344 +40,6 @@ Following [Switch Dreams's](https://www.switchdreams.com.br/]) coding practices,
|
|
34
40
|
- Select fields
|
35
41
|
- User auth module
|
36
42
|
|
37
|
-
## Installation
|
38
|
-
|
39
|
-
Add this line to your application's Gemfile:
|
40
|
-
|
41
|
-
```ruby
|
42
|
-
# Build a Ruby on Rails REST API faster
|
43
|
-
gem 'rest-api-generator'
|
44
|
-
```
|
45
|
-
|
46
|
-
And then execute:
|
47
|
-
|
48
|
-
$ bundle install
|
49
|
-
|
50
|
-
Or install it yourself as:
|
51
|
-
|
52
|
-
$ gem install rest-api-generator
|
53
|
-
|
54
|
-
## Requirements
|
55
|
-
|
56
|
-
1. You need to have installed RSpec and FactoryBot in your application.
|
57
|
-
|
58
|
-
<ul>
|
59
|
-
<li>RSpec: https://github.com/rspec/rspec-rails</li>
|
60
|
-
<li>Factory bot: https://github.com/thoughtbot/factory_bot_rails</li>
|
61
|
-
</ul>
|
62
|
-
|
63
|
-
2. Include in ApplicationController the error handler module:
|
64
|
-
|
65
|
-
```ruby
|
66
|
-
|
67
|
-
class ApplicationController < ActionController::API
|
68
|
-
include RestApiGenerator::ErrorHandler
|
69
|
-
end
|
70
|
-
```
|
71
|
-
|
72
|
-
This error handler will rescue from: `ActiveRecord::RecordNotFound`
|
73
|
-
, `ActiveRecord::ActiveRecordError`, `ActiveRecord::RecordInvalid`, `ActiveModel::ValidationError`
|
74
|
-
, `RestApiGenerator::CustomError`.
|
75
|
-
|
76
|
-
## Usage
|
77
|
-
|
78
|
-
### Generate Resource
|
79
|
-
|
80
|
-
```bash
|
81
|
-
$ rails g rest_api_generator:resource table_name attributes
|
82
|
-
```
|
83
|
-
|
84
|
-
This command will create:
|
85
|
-
|
86
|
-
- **Model and Migration**: Using rails default model generator
|
87
|
-
- **Controller**: A controller that implementes CRUD by inheritance of `RestApiGenerator::ResourceController`, or you
|
88
|
-
can use eject option for create a controller
|
89
|
-
that implements index, show, create, update and destroy methods.
|
90
|
-
- **Specs for the created controller**
|
91
|
-
- **Factory bot factory for created model**
|
92
|
-
- **Routes**: with rails resources
|
93
|
-
|
94
|
-
### Example
|
95
|
-
|
96
|
-
```bash
|
97
|
-
$ rails g rest_api_generator:resource car name:string color:string
|
98
|
-
```
|
99
|
-
|
100
|
-
Will generate following controller and the other files:
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
# app/controllers/cars_controller.rb
|
104
|
-
class CarsController < RestApiGenerator::ResourceController
|
105
|
-
end
|
106
|
-
```
|
107
|
-
|
108
|
-
For a better experience you can override some methods from the
|
109
|
-
[default controller](https://github.com/SwitchDreams/rest-api-generator/blob/main/lib/rest_api_generator/resource_controller.rb)
|
110
|
-
|
111
|
-
### Options
|
112
|
-
|
113
|
-
| Option | Goal | Default | Usage Example |
|
114
|
-
|--------|--------------------------------------------------------------|---------|-----------------|
|
115
|
-
| father | Generate nested resource | nil | --father Users |
|
116
|
-
| scope | Scope the resource for other route or namespace organization | nil | --scope Api::V1 |
|
117
|
-
| eject | Eject the controller to high customization | false | true |
|
118
|
-
| spec | Choose the spec format. Current options: "rspec" or "rswag" | rspec | --spec rswag |
|
119
|
-
|
120
|
-
#### Scope
|
121
|
-
|
122
|
-
In REST api one of the best practices is versioning the end-points, and you can achieve this using scope options,
|
123
|
-
example:
|
124
|
-
|
125
|
-
```bash
|
126
|
-
# Command
|
127
|
-
rails g rest_api_generator:resource car name:string color:string --scope Api::V1
|
128
|
-
```
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
# GET api/v1/cars
|
132
|
-
module Api::V1
|
133
|
-
class CarsController < RestApiGenerator::ResourceController
|
134
|
-
end
|
135
|
-
end
|
136
|
-
```
|
137
|
-
|
138
|
-
For this option you need to manually setup routes, for this example:
|
139
|
-
|
140
|
-
```ruby
|
141
|
-
# routes.rb
|
142
|
-
namespace :api do
|
143
|
-
namespace :v1 do
|
144
|
-
resources :cars
|
145
|
-
end
|
146
|
-
end
|
147
|
-
```
|
148
|
-
|
149
|
-
#### Nested resource
|
150
|
-
|
151
|
-
In REST api sometimes we need to build a nested resource, for example when we need to get all devices from a user, for
|
152
|
-
this we have nested resource option:
|
153
|
-
|
154
|
-
```bash
|
155
|
-
# Command
|
156
|
-
rails g rest_api_generator:resource Devices name:string color:string users:references --scope Users
|
157
|
-
```
|
158
|
-
|
159
|
-
```ruby
|
160
|
-
# GET users/:user_id/devices
|
161
|
-
module Users
|
162
|
-
class DevicesController < RestApiGenerator::ChildResourceController
|
163
|
-
end
|
164
|
-
end
|
165
|
-
```
|
166
|
-
|
167
|
-
For this option you need to manually setup routes, for this example:
|
168
|
-
|
169
|
-
```ruby
|
170
|
-
# routes.rb
|
171
|
-
resources :users do
|
172
|
-
resources :devices, controller: 'users/devices'
|
173
|
-
end
|
174
|
-
```
|
175
|
-
|
176
|
-
Considerations:
|
177
|
-
|
178
|
-
- The children model needs to belongs_to parent model and parent model needs to have has_many children model
|
179
|
-
|
180
|
-
#### Eject
|
181
|
-
|
182
|
-
Or you can use the `eject` option for create the controller with the implemented methods:
|
183
|
-
|
184
|
-
```bash
|
185
|
-
rails g rest_api_generator:resource car name:string color:string --eject true
|
186
|
-
```
|
187
|
-
|
188
|
-
```ruby
|
189
|
-
|
190
|
-
class CarsController < ApplicationController
|
191
|
-
before_action :set_car, only: %i[show update destroy]
|
192
|
-
|
193
|
-
def index
|
194
|
-
@car = Car.all
|
195
|
-
render json: @car, status: :ok
|
196
|
-
end
|
197
|
-
|
198
|
-
def show
|
199
|
-
render json: @car, status: :ok
|
200
|
-
end
|
201
|
-
|
202
|
-
def create
|
203
|
-
@car = Car.create!(car_params)
|
204
|
-
render json: @car, status: :created
|
205
|
-
end
|
206
|
-
|
207
|
-
def update
|
208
|
-
@car = Car.update!(car_params)
|
209
|
-
render json: @car, status: :ok
|
210
|
-
end
|
211
|
-
|
212
|
-
def destroy
|
213
|
-
@car.destroy!
|
214
|
-
end
|
215
|
-
|
216
|
-
private
|
217
|
-
|
218
|
-
def set_car
|
219
|
-
@car = Car.find(params[:id])
|
220
|
-
end
|
221
|
-
|
222
|
-
def car_params
|
223
|
-
params.require(:car).permit(:name, :color)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
```
|
227
|
-
|
228
|
-
#### Specs/Docs
|
229
|
-
|
230
|
-
The default generated spec for this gem is using plain rspec, but you can choose rswag, for scaffold you specs and docs
|
231
|
-
at the same time:
|
232
|
-
|
233
|
-
For this you need to setup https://github.com/rswag/rswag and you the following flag when generating resources.
|
234
|
-
|
235
|
-
```shell
|
236
|
-
rails g rest_api_generator:resource Car name:string color:string --spec rswag
|
237
|
-
```
|
238
|
-
|
239
|
-
This spec options work as generators too, so you can call them individually:
|
240
|
-
|
241
|
-
```shell
|
242
|
-
# rest_api_generator:spec:rswag or rest_api_generator:spec:rspec
|
243
|
-
rails g rest_api_generator:spec:rswag Car name:string color:string
|
244
|
-
```
|
245
|
-
|
246
|
-
#### Configuration for specs
|
247
|
-
|
248
|
-
By default, the plain rspec and rswag specs are going to be generated in the _spec/requests_ and _spec/docs_
|
249
|
-
directories, respectively. You can override using the (config options)[#configuration]]. :
|
250
|
-
|
251
|
-
### Resource Features
|
252
|
-
|
253
|
-
#### Modular Error Handler
|
254
|
-
|
255
|
-
The error module will return a json in this following format when any active record or custom error raises.
|
256
|
-
|
257
|
-
```json
|
258
|
-
{
|
259
|
-
"status": 422,
|
260
|
-
"error": "",
|
261
|
-
"message": ""
|
262
|
-
}
|
263
|
-
```
|
264
|
-
|
265
|
-
This is good to padronize the error handler in front-end too.
|
266
|
-
|
267
|
-
#### Ordering
|
268
|
-
|
269
|
-
For ordering use this format:
|
270
|
-
|
271
|
-
- Ordering asc: `GET /cars?sort=+name or GET /cars?sort=name`
|
272
|
-
- Ordering desc: `GET /card?sort=-name`
|
273
|
-
|
274
|
-
By default, every resource column can be the key for ordering.
|
275
|
-
|
276
|
-
#### Filtering
|
277
|
-
|
278
|
-
For filter is needed to add some scopes in Model file, example:
|
279
|
-
|
280
|
-
```ruby
|
281
|
-
# app/models/car.rb
|
282
|
-
|
283
|
-
class Car < ApplicationRecord
|
284
|
-
include RestApiGenerator::Filterable
|
285
|
-
|
286
|
-
filter_scope :filter_by_color, ->(color) { where(color: color) }
|
287
|
-
filter_scope :filter_by_name, ->(name) { where("name LIKE ?", "%#{name}%") }
|
288
|
-
end
|
289
|
-
```
|
290
|
-
|
291
|
-
And It's done, you can filter your index end-point:
|
292
|
-
|
293
|
-
- `GET /cars?color=blue or GET /cars?color=red&name=Ferrari`
|
294
|
-
|
295
|
-
### Pagination
|
296
|
-
|
297
|
-
For pagination, you need to create pagy initialializer file (pagy.rb) in the config directory of your project.
|
298
|
-
Follow [pagy's example](https://ddnexus.github.io/pagy/quick-start/) for more information.
|
299
|
-
|
300
|
-
Next, you should add some lines on top of the previously created pagy file:
|
301
|
-
|
302
|
-
```ruby
|
303
|
-
# config/initializers/pagy.rb
|
304
|
-
require "pagy"
|
305
|
-
require "pagy/extras/headers"
|
306
|
-
```
|
307
|
-
|
308
|
-
At last, change the pagination variable on RestApiGenerator initializer to true;
|
309
|
-
|
310
|
-
```rb
|
311
|
-
# config/initializers/rest_api_generator.rb
|
312
|
-
config.pagination = true # default: false
|
313
|
-
```
|
314
|
-
|
315
|
-
Note, if the parent controller is changed, it is necessary to include Pagy::Backend in the new parent.
|
316
|
-
|
317
|
-
```rb
|
318
|
-
# new_parent_controller.rb
|
319
|
-
class NewParentController < ActionController::Base
|
320
|
-
include Pagy::Backend
|
321
|
-
end
|
322
|
-
```
|
323
|
-
|
324
|
-
### Serialization
|
325
|
-
|
326
|
-
If you are working with [ams](https://github.com/rails-api/active_model_serializers), the serializer will work without
|
327
|
-
any extra configuration.
|
328
|
-
But if you need to customize you can override the serializer method in the controller:
|
329
|
-
|
330
|
-
```ruby
|
331
|
-
# Example with panko serializer: https://github.com/panko-serializer/panko_serializer
|
332
|
-
class CarsController < RestApiGenerator::ResourceController
|
333
|
-
|
334
|
-
# serializer used in show, create, update.
|
335
|
-
def serializer(resource)
|
336
|
-
Panko::CarSerializer.new.serialize_to_json(resource)
|
337
|
-
end
|
338
|
-
|
339
|
-
# serializer used in index.
|
340
|
-
def index_serializer(resources)
|
341
|
-
Panko::ArraySerializer.new(resources, each_serializer: Panko::CarSerializer).to_json
|
342
|
-
end
|
343
|
-
end
|
344
|
-
```
|
345
|
-
|
346
|
-
```ruby
|
347
|
-
# Example with ams
|
348
|
-
class CarsController < RestApiGenerator::ResourceController
|
349
|
-
def serializer(resource)
|
350
|
-
ActiveModelSerializers::SerializableResource.new(resource, each_serializer: Ams::CarSerializer).to_json
|
351
|
-
end
|
352
|
-
end
|
353
|
-
```
|
354
|
-
|
355
|
-
The gem is tested with [panko serializer](https://github.com/panko-serializer/panko_serializer)
|
356
|
-
and [ams](https://github.com/rails-api/active_model_serializers). But should works with any serializer, feel free to add
|
357
|
-
tests for your favorite serializer.
|
358
|
-
|
359
|
-
## Configuration
|
360
|
-
|
361
|
-
You can override this gem configuration using the initializer or any other method
|
362
|
-
from [anyway_config](https://github.com/palkan/anyway_config):
|
363
|
-
|
364
|
-
```rb
|
365
|
-
# config/initializers/rest_api_generator.rb
|
366
|
-
|
367
|
-
RestApiGenerator.configure do |config|
|
368
|
-
config.test_path = "custom_test_dir/requests" # default: spec/requests
|
369
|
-
config.docs_path = "custom_docs_dir/rswag" # default: spec/docs
|
370
|
-
config.parent_class = "ApplicationController" # default: RestApiGenerator::ResourceController
|
371
|
-
config.pagination = true # default: false
|
372
|
-
end
|
373
|
-
```
|
374
|
-
|
375
43
|
## Development
|
376
44
|
|
377
45
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module RestApiGenerator
|
4
4
|
class ChildResourceController < RestApiGenerator.configuration.parent_controller.constantize
|
5
|
+
include ControllerCallbacks
|
5
6
|
include Orderable
|
6
7
|
include Serializable
|
7
8
|
|
@@ -74,11 +75,15 @@ module RestApiGenerator
|
|
74
75
|
|
75
76
|
# Before actions
|
76
77
|
def set_parent_resource
|
77
|
-
|
78
|
+
run_callbacks :set_parent_resource do
|
79
|
+
@parent_resource = parent_resource_class.find(parent_record_id)
|
80
|
+
end
|
78
81
|
end
|
79
82
|
|
80
83
|
def set_resource
|
81
|
-
|
84
|
+
run_callbacks :set_resource do
|
85
|
+
@resource = resources.find(record_id)
|
86
|
+
end
|
82
87
|
end
|
83
88
|
|
84
89
|
# UsersController => User
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module RestApiGenerator
|
4
4
|
class ResourceController < RestApiGenerator.configuration.parent_controller.constantize
|
5
|
+
include ControllerCallbacks
|
5
6
|
include Orderable
|
6
7
|
include Serializable
|
7
8
|
|
8
9
|
before_action :set_resource, only: [:show, :update, :destroy]
|
9
|
-
|
10
10
|
def index
|
11
11
|
@resources = resource_class.all
|
12
12
|
@resources = @resources.filter_resource(params_for_filter) if resource_class.include?(Filterable)
|
@@ -63,7 +63,9 @@ module RestApiGenerator
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def set_resource
|
66
|
-
|
66
|
+
run_callbacks :set_resource do
|
67
|
+
@resource = resource_class.find(record_id)
|
68
|
+
end
|
67
69
|
end
|
68
70
|
|
69
71
|
# UsersController => User
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RestApiGenerator
|
4
|
+
module ControllerCallbacks
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include ActiveSupport::Callbacks
|
7
|
+
|
8
|
+
included do
|
9
|
+
define_callbacks :set_resource
|
10
|
+
define_callbacks :set_parent_resource
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Code from rails source code
|
15
|
+
[:before, :after, :around].each do |callback|
|
16
|
+
define_method "#{callback}_set_resource" do |*names, &blk|
|
17
|
+
_insert_callbacks(names, blk) do |name, options|
|
18
|
+
set_callback(:set_resource, callback, name, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method "#{callback}_set_parent_resource" do |*names, &blk|
|
23
|
+
_insert_callbacks(names, blk) do |name, options|
|
24
|
+
set_callback(:set_parent_resource, callback, name, options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/rest_api_generator.rb
CHANGED
@@ -9,6 +9,7 @@ require_relative "rest_api_generator/helpers/render"
|
|
9
9
|
require_relative "rest_api_generator/filterable"
|
10
10
|
require_relative "rest_api_generator/orderable"
|
11
11
|
require_relative "rest_api_generator/serializable"
|
12
|
+
require_relative "rest_api_generator/controller_callbacks"
|
12
13
|
|
13
14
|
module RestApiGenerator
|
14
15
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-api-generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- PedroAugustoRamalhoDuarte
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anyway_config
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- lib/rest-api-generator.rb
|
156
156
|
- lib/rest_api_generator.rb
|
157
157
|
- lib/rest_api_generator/config.rb
|
158
|
+
- lib/rest_api_generator/controller_callbacks.rb
|
158
159
|
- lib/rest_api_generator/custom_error.rb
|
159
160
|
- lib/rest_api_generator/error_handler.rb
|
160
161
|
- lib/rest_api_generator/filterable.rb
|