easy-peasy-api 0.1.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 +7 -0
- data/README.md +206 -0
- data/lib/easy_peasy_api/application_controller.rb +41 -0
- data/lib/easy_peasy_api/configuration.rb +34 -0
- data/lib/easy_peasy_api/middleware.rb +151 -0
- data/lib/easy_peasy_api/railtie.rb +9 -0
- data/lib/easy_peasy_api/version.rb +3 -0
- data/lib/easy_peasy_api/version.rb.erb +3 -0
- data/lib/easy_peasy_api.rb +22 -0
- metadata +116 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5863a5ef0b82d5420acdf6a93d9a085bce84b0b4c3ce72b389e1a2f3460ae5c9
|
|
4
|
+
data.tar.gz: d645b973b0dd6d79f366361a9cb52a1089981c275dafa540396b2a9308d44f34
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1ffa616b4cadc9b82043e156ffe6c16b9e32bd9cdc25a131be8f1dafba72f5e17cb2fcc36fea88dcbd0008efdcd2a8480bd9e801a0b9f493f637baeb4fc624e7
|
|
7
|
+
data.tar.gz: 48487fd1ce5ef02a6b6cba144602baebad61b6bef0a9eadd57695d3f9338f1385fc0661589e632dbb2527e60154438c2df2eeb84f0d1e9acd6a4aa292bb46301
|
data/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# easy-peasy-api
|
|
2
|
+
|
|
3
|
+
Filesystem-based API routing for Rails. Drop controller files into a directory and they become API endpoints automatically. No `routes.rb` entries needed.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Gemfile
|
|
9
|
+
gem "easy-peasy-api", require: "easy_peasy_api"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
# config/initializers/easy_peasy_api.rb
|
|
14
|
+
EasyPeasyApi.configure do |config|
|
|
15
|
+
config.path = "/api/v1"
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
That's it. Every controller under `app/controllers/api/v1/` is now a live endpoint.
|
|
20
|
+
|
|
21
|
+
## How it works
|
|
22
|
+
|
|
23
|
+
The URL maps directly to the filesystem. The HTTP method determines the action.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
URL Controller File Action
|
|
27
|
+
───────────────────────────────────── ───────────────────────────────────────────────────────── ──────
|
|
28
|
+
GET /api/v1/customers app/controllers/api/v1/customers_controller.rb #index
|
|
29
|
+
POST /api/v1/customers app/controllers/api/v1/customers_controller.rb #create
|
|
30
|
+
GET /api/v1/customers/42 app/controllers/api/v1/customers_controller.rb #show
|
|
31
|
+
PUT /api/v1/customers/42 app/controllers/api/v1/customers_controller.rb #update
|
|
32
|
+
DELETE /api/v1/customers/42 app/controllers/api/v1/customers_controller.rb #destroy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Nest directories for nested resources:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
GET /api/v1/customers/uncontacted app/controllers/api/v1/customers/uncontacted_controller.rb #index
|
|
39
|
+
GET /api/v1/customers/uncontacted/7 app/controllers/api/v1/customers/uncontacted_controller.rb #show
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Dynamic segments in the middle just work:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
GET /api/v1/customers/42/notes app/controllers/api/v1/customers/notes_controller.rb #index
|
|
46
|
+
GET /api/v1/customers/42/notes/99 app/controllers/api/v1/customers/notes_controller.rb #show
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `42` becomes `params[:customer_id]` (singularized parent directory + `_id`). The `99` becomes `params[:id]`.
|
|
50
|
+
|
|
51
|
+
## Examples
|
|
52
|
+
|
|
53
|
+
### Basic controller
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# app/controllers/api/v1/customers_controller.rb
|
|
57
|
+
module Api::V1
|
|
58
|
+
class CustomersController < ActionController::API
|
|
59
|
+
def index
|
|
60
|
+
render json: Customer.all
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def show
|
|
64
|
+
render json: Customer.find(params[:id])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def create
|
|
68
|
+
customer = Customer.create!(customer_params)
|
|
69
|
+
render json: customer, status: :created
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def update
|
|
73
|
+
customer = Customer.find(params[:id])
|
|
74
|
+
customer.update!(customer_params)
|
|
75
|
+
render json: customer
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def destroy
|
|
79
|
+
Customer.find(params[:id]).destroy!
|
|
80
|
+
head :no_content
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def customer_params
|
|
86
|
+
params.permit(:name, :email)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
curl localhost:3000/api/v1/customers
|
|
94
|
+
curl localhost:3000/api/v1/customers/42
|
|
95
|
+
curl -X POST localhost:3000/api/v1/customers -d '{"name":"Acme"}' -H 'Content-Type: application/json'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Nested resource with dynamic parent ID
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
# app/controllers/api/v1/customers/notes_controller.rb
|
|
102
|
+
module Api::V1::Customers
|
|
103
|
+
class NotesController < ActionController::API
|
|
104
|
+
def index
|
|
105
|
+
customer = Customer.find(params[:customer_id])
|
|
106
|
+
render json: customer.notes
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def show
|
|
110
|
+
note = Note.find(params[:id])
|
|
111
|
+
render json: note
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
curl localhost:3000/api/v1/customers/42/notes # params[:customer_id] = "42"
|
|
119
|
+
curl localhost:3000/api/v1/customers/42/notes/99 # params[:customer_id] = "42", params[:id] = "99"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Deeper nesting
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
# app/controllers/api/v1/customers/uncontacted/notes_controller.rb
|
|
126
|
+
module Api::V1::Customers::Uncontacted
|
|
127
|
+
class NotesController < ActionController::API
|
|
128
|
+
def index
|
|
129
|
+
render json: Note.where(uncontacted_id: params[:uncontacted_id])
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def show
|
|
133
|
+
render json: Note.find(params[:id])
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
curl localhost:3000/api/v1/customers/uncontacted/55/notes # params[:uncontacted_id] = "55"
|
|
141
|
+
curl localhost:3000/api/v1/customers/uncontacted/55/notes/12 # params[:uncontacted_id] = "55", params[:id] = "12"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Renaming params with `set_params`
|
|
145
|
+
|
|
146
|
+
Dynamic segments are auto-named after the parent directory (singularized + `_id`). Sometimes that default name doesn't match your domain. Inherit from `EasyPeasyApi::ApplicationController` and call `set_params` in the action to rename them:
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
# app/controllers/api/v1/customers/notes_controller.rb
|
|
150
|
+
#
|
|
151
|
+
# URL: /api/v1/customers/42/notes/99
|
|
152
|
+
# Default params: customer_id=42, id=99
|
|
153
|
+
# After set_params: account_id=42, id=99
|
|
154
|
+
module Api::V1::Customers
|
|
155
|
+
class NotesController < EasyPeasyApi::ApplicationController
|
|
156
|
+
def index
|
|
157
|
+
set_params :account_id
|
|
158
|
+
render json: Note.where(account_id: params[:account_id])
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def show
|
|
162
|
+
set_params :account_id, :id
|
|
163
|
+
render json: Note.find_by(account_id: params[:account_id], id: params[:id])
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
curl localhost:3000/api/v1/customers/42/notes
|
|
171
|
+
# Without set_params: params[:customer_id] = "42"
|
|
172
|
+
# With set_params: params[:account_id] = "42"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`set_params` maps names to dynamic segment values in the order they appear in the URL. Call it in the action, or in a `before_action`. It rebuilds params each time, so you can call it as many times as you need.
|
|
176
|
+
|
|
177
|
+
## Param naming rules
|
|
178
|
+
|
|
179
|
+
| URL pattern | Default param name | Rule |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| `/customers/42` | `params[:id]` | Trailing segment after a controller |
|
|
182
|
+
| `/customers/42/notes` | `params[:customer_id]` | Mid-path segment, named from parent dir (singularized + `_id`) |
|
|
183
|
+
| `/customers/42/notes/99` | `params[:customer_id]`, `params[:id]` | Both rules combined |
|
|
184
|
+
|
|
185
|
+
## Route priority
|
|
186
|
+
|
|
187
|
+
When a URL segment could match either a nested controller or a dynamic `:id`, the more specific match (nested controller) wins:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
app/controllers/api/v1/customers_controller.rb
|
|
191
|
+
app/controllers/api/v1/customers/uncontacted_controller.rb
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
GET /api/v1/customers/uncontacted -> UncontactedController#index (not CustomersController#show)
|
|
196
|
+
GET /api/v1/customers/42 -> CustomersController#show (no matching nested controller)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Action mapping
|
|
200
|
+
|
|
201
|
+
| HTTP method | With `:id` | Without `:id` |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| GET | `show` | `index` |
|
|
204
|
+
| POST | -- | `create` |
|
|
205
|
+
| PUT / PATCH | `update` | -- |
|
|
206
|
+
| DELETE | `destroy` | -- |
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module EasyPeasyApi
|
|
2
|
+
class ApplicationController < ActionController::API
|
|
3
|
+
before_action :set_default_params
|
|
4
|
+
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
# Called automatically. Applies the middleware's default param names.
|
|
8
|
+
def set_default_params
|
|
9
|
+
default_names = request.env['easy_peasy_api.default_param_names']
|
|
10
|
+
values = request.env['easy_peasy_api.dynamic_values']
|
|
11
|
+
return unless default_names && values
|
|
12
|
+
|
|
13
|
+
set_params(*default_names)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Rebuild path_parameters with the given names mapped to the ordered
|
|
17
|
+
# dynamic segment values the middleware extracted from the URL.
|
|
18
|
+
#
|
|
19
|
+
# Call this inside any action (or a before_action) to rename params:
|
|
20
|
+
#
|
|
21
|
+
# def show
|
|
22
|
+
# set_params :customer_id, :id
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
def set_params(*names)
|
|
26
|
+
values = request.env['easy_peasy_api.dynamic_values']
|
|
27
|
+
return unless values
|
|
28
|
+
|
|
29
|
+
path_params = {
|
|
30
|
+
controller: request.path_parameters[:controller],
|
|
31
|
+
action: request.path_parameters[:action]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
names.each_with_index do |name, i|
|
|
35
|
+
path_params[name.to_sym] = values[i] if i < values.length
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
request.path_parameters = path_params
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module EasyPeasyApi
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :path
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@path = nil
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Returns the path with leading slash, no trailing slash
|
|
10
|
+
def normalized_path
|
|
11
|
+
return nil unless @path
|
|
12
|
+
|
|
13
|
+
p = @path.to_s
|
|
14
|
+
p = "/#{p}" unless p.start_with?('/')
|
|
15
|
+
p.chomp('/')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Converts the configured path to a module prefix
|
|
19
|
+
# e.g. "/api/v1" => "Api::V1"
|
|
20
|
+
def controller_module_prefix
|
|
21
|
+
return nil unless normalized_path
|
|
22
|
+
|
|
23
|
+
normalized_path.delete_prefix('/').split('/').map { |s| s.camelize }.join('::')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns the filesystem directory under app/controllers for this path
|
|
27
|
+
# e.g. "/api/v1" => "api/v1"
|
|
28
|
+
def controller_directory
|
|
29
|
+
return nil unless normalized_path
|
|
30
|
+
|
|
31
|
+
normalized_path.delete_prefix('/')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'action_dispatch'
|
|
2
|
+
require 'active_support/inflector'
|
|
3
|
+
|
|
4
|
+
module EasyPeasyApi
|
|
5
|
+
class Middleware
|
|
6
|
+
def initialize(app)
|
|
7
|
+
@app = app
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(env)
|
|
11
|
+
config = EasyPeasyApi.configuration
|
|
12
|
+
prefix = config&.normalized_path
|
|
13
|
+
|
|
14
|
+
return @app.call(env) unless prefix
|
|
15
|
+
|
|
16
|
+
request_path = env['PATH_INFO'].to_s
|
|
17
|
+
|
|
18
|
+
return @app.call(env) unless path_matches?(request_path, prefix)
|
|
19
|
+
|
|
20
|
+
relative = request_path.delete_prefix(prefix).delete_prefix('/')
|
|
21
|
+
return @app.call(env) if relative.empty?
|
|
22
|
+
|
|
23
|
+
segments = relative.split('/').reject(&:empty?)
|
|
24
|
+
return @app.call(env) if segments.empty?
|
|
25
|
+
|
|
26
|
+
resolution = resolve(segments, config)
|
|
27
|
+
return not_found unless resolution
|
|
28
|
+
|
|
29
|
+
controller_class, dynamic_pairs = resolution
|
|
30
|
+
|
|
31
|
+
# dynamic_pairs is an ordered array of [default_name, value]
|
|
32
|
+
# e.g. [[:uncontacted_id, "234234"], [:id, "999"]]
|
|
33
|
+
has_id = dynamic_pairs.any? { |name, _| name == :id }
|
|
34
|
+
|
|
35
|
+
request_method = env['REQUEST_METHOD']
|
|
36
|
+
action = determine_action(request_method, has_id)
|
|
37
|
+
return method_not_allowed unless action
|
|
38
|
+
|
|
39
|
+
dispatch(controller_class, action, dynamic_pairs, env)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def path_matches?(request_path, prefix)
|
|
45
|
+
request_path == prefix || request_path.start_with?("#{prefix}/")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def resolve(segments, config)
|
|
49
|
+
controllers_root = Rails.root.join('app', 'controllers', config.controller_directory).to_s
|
|
50
|
+
mod_prefix = config.controller_module_prefix
|
|
51
|
+
|
|
52
|
+
result = walk(segments, controllers_root, [], [], nil)
|
|
53
|
+
return nil unless result
|
|
54
|
+
|
|
55
|
+
controller_segments, dynamic_pairs = result
|
|
56
|
+
klass = constantize_controller(mod_prefix, controller_segments)
|
|
57
|
+
return nil unless klass
|
|
58
|
+
|
|
59
|
+
[klass, dynamic_pairs]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Recursive filesystem walk.
|
|
63
|
+
#
|
|
64
|
+
# Returns [controller_segments, dynamic_pairs] where dynamic_pairs is
|
|
65
|
+
# an ordered array of [default_param_name, value].
|
|
66
|
+
def walk(segments, current_dir, controller_segments, dynamic_pairs, last_dir_name)
|
|
67
|
+
return nil if segments.empty?
|
|
68
|
+
|
|
69
|
+
segment = segments.first
|
|
70
|
+
rest = segments[1..]
|
|
71
|
+
|
|
72
|
+
controller_file = File.join(current_dir, "#{segment}_controller.rb")
|
|
73
|
+
has_controller = File.exist?(controller_file)
|
|
74
|
+
subdir = File.join(current_dir, segment)
|
|
75
|
+
has_directory = File.directory?(subdir)
|
|
76
|
+
|
|
77
|
+
# 1. Try descending into a subdirectory first (most specific match wins)
|
|
78
|
+
if has_directory
|
|
79
|
+
result = walk(rest, subdir, controller_segments + [segment], dynamic_pairs, segment)
|
|
80
|
+
return result if result
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# 2. Try matching a controller file
|
|
84
|
+
if has_controller
|
|
85
|
+
found_segments = controller_segments + [segment]
|
|
86
|
+
|
|
87
|
+
if rest.empty?
|
|
88
|
+
return [found_segments, dynamic_pairs]
|
|
89
|
+
elsif rest.length == 1
|
|
90
|
+
return [found_segments, dynamic_pairs + [[:id, rest.first]]]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# 3. No directory or controller match — dynamic param
|
|
95
|
+
if last_dir_name
|
|
96
|
+
param_name = :"#{last_dir_name.singularize}_id"
|
|
97
|
+
return walk(rest, current_dir, controller_segments, dynamic_pairs + [[param_name, segment]], last_dir_name)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def constantize_controller(mod_prefix, segments)
|
|
104
|
+
class_name = segments.map { |s| s.camelize }.join('::')
|
|
105
|
+
full_name = "#{mod_prefix}::#{class_name}Controller"
|
|
106
|
+
full_name.constantize
|
|
107
|
+
rescue NameError
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def dispatch(controller_class, action, dynamic_pairs, env)
|
|
112
|
+
default_names = dynamic_pairs.map(&:first)
|
|
113
|
+
values = dynamic_pairs.map(&:last)
|
|
114
|
+
|
|
115
|
+
# Store ordered data for set_params
|
|
116
|
+
env['easy_peasy_api.dynamic_values'] = values
|
|
117
|
+
env['easy_peasy_api.default_param_names'] = default_names
|
|
118
|
+
|
|
119
|
+
# Set path_parameters with default names so it works out of the box
|
|
120
|
+
path_params = { controller: controller_class.controller_path, action: action.to_s }
|
|
121
|
+
dynamic_pairs.each { |name, value| path_params[name] = value }
|
|
122
|
+
|
|
123
|
+
env['action_dispatch.request.path_parameters'] = path_params
|
|
124
|
+
|
|
125
|
+
controller_class.action(action).call(env)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def determine_action(method, has_id)
|
|
129
|
+
if has_id
|
|
130
|
+
case method
|
|
131
|
+
when 'GET' then :show
|
|
132
|
+
when 'PUT', 'PATCH' then :update
|
|
133
|
+
when 'DELETE' then :destroy
|
|
134
|
+
end
|
|
135
|
+
else
|
|
136
|
+
case method
|
|
137
|
+
when 'GET' then :index
|
|
138
|
+
when 'POST' then :create
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def not_found
|
|
144
|
+
[404, { 'content-type' => 'application/json' }, ['{"error":"Not Found"}']]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def method_not_allowed
|
|
148
|
+
[405, { 'content-type' => 'application/json' }, ['{"error":"Method Not Allowed"}']]
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'easy_peasy_api/version'
|
|
2
|
+
require 'easy_peasy_api/configuration'
|
|
3
|
+
require 'easy_peasy_api/middleware'
|
|
4
|
+
require 'easy_peasy_api/railtie' if defined?(Rails::Railtie)
|
|
5
|
+
|
|
6
|
+
module EasyPeasyApi
|
|
7
|
+
class << self
|
|
8
|
+
def configuration
|
|
9
|
+
@configuration ||= Configuration.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def configure
|
|
13
|
+
yield(configuration)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def reset_configuration!
|
|
17
|
+
@configuration = Configuration.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
require 'easy_peasy_api/application_controller' if defined?(ActionController::API)
|
metadata
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: easy-peasy-api
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Nathan
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: actionpack
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: railties
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '7.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '7.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: minitest
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '5.0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '5.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rack-test
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '2.0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '2.0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rails
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '7.0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '7.0'
|
|
82
|
+
description: A Rails Railtie that dynamically routes API requests to controllers based
|
|
83
|
+
on the filesystem structure.
|
|
84
|
+
executables: []
|
|
85
|
+
extensions: []
|
|
86
|
+
extra_rdoc_files: []
|
|
87
|
+
files:
|
|
88
|
+
- README.md
|
|
89
|
+
- lib/easy_peasy_api.rb
|
|
90
|
+
- lib/easy_peasy_api/application_controller.rb
|
|
91
|
+
- lib/easy_peasy_api/configuration.rb
|
|
92
|
+
- lib/easy_peasy_api/middleware.rb
|
|
93
|
+
- lib/easy_peasy_api/railtie.rb
|
|
94
|
+
- lib/easy_peasy_api/version.rb
|
|
95
|
+
- lib/easy_peasy_api/version.rb.erb
|
|
96
|
+
licenses:
|
|
97
|
+
- MIT
|
|
98
|
+
metadata: {}
|
|
99
|
+
rdoc_options: []
|
|
100
|
+
require_paths:
|
|
101
|
+
- lib
|
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: '3.0'
|
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '0'
|
|
112
|
+
requirements: []
|
|
113
|
+
rubygems_version: 3.7.2
|
|
114
|
+
specification_version: 4
|
|
115
|
+
summary: Filesystem-based API routing for Rails
|
|
116
|
+
test_files: []
|