fit_api 1.1.2 → 1.1.3
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/Gemfile +1 -1
- data/README.md +44 -48
- data/lib/fit_api.rb +8 -6
- data/lib/fit_api/controller.rb +52 -17
- data/lib/fit_api/router.rb +24 -15
- data/lib/fit_api/router/mapper.rb +14 -11
- data/lib/fit_api/router/params.rb +21 -38
- data/lib/fit_api/router/parser.rb +5 -3
- data/lib/fit_api/router/route.rb +31 -50
- data/lib/fit_api/version.rb +3 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5922975501ebc48453cb5a6f7ad438befbe85d0b
|
4
|
+
data.tar.gz: 9d93fc4af41f39e28581820d75d699d0638c9ce6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88eb8fa868fd5e0084a81c3bb4ed2e1672b128b27f6be74914cda3f13d527dae03d4dd54e167551473ef8b91317218f6e3ad898fe229e4361a41d9c5b21e4d52
|
7
|
+
data.tar.gz: c9e11e13e75c4f5bf4a88ac62b63a73c198be62b77a07810635ee959d434cde146db11218c40b7b9a0df06b4285cf00974723ae7bb2f3e28c466fa4ccd30e981
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# fit-api
|
2
2
|
|
3
|
-
Lightweight framework for building JSON API
|
3
|
+
Lightweight framework for building JSON API"s
|
4
4
|
|
5
5
|
## Introduction
|
6
6
|
|
@@ -37,63 +37,61 @@ $ gem install fit_api
|
|
37
37
|
## Usage
|
38
38
|
|
39
39
|
This is a basic example showing how it works... you can check the demo app from this repository:
|
40
|
-
[fit-api-demo](http://github.com/bermanya/
|
40
|
+
[fit-api-demo](http://github.com/bermanya/minesweeper-api)
|
41
41
|
|
42
42
|
**api.rb**
|
43
43
|
|
44
44
|
```ruby
|
45
|
-
|
45
|
+
# optional:
|
46
|
+
FitApi::Router.auto_load_path "controllers"
|
46
47
|
|
47
48
|
FitApi::Router.define do
|
48
|
-
get
|
49
|
+
get "/:name", to: "app#show"
|
49
50
|
|
50
|
-
root to:
|
51
|
+
root to: "app#index"
|
51
52
|
end
|
53
|
+
```
|
54
|
+
|
55
|
+
**controllers/app_controllers.rb**
|
52
56
|
|
57
|
+
```
|
53
58
|
class AppController < FitApi::Controller
|
54
59
|
def index
|
55
|
-
json(
|
60
|
+
json(message: "Hello world")
|
56
61
|
end
|
57
62
|
|
58
63
|
def show
|
59
|
-
|
64
|
+
if found
|
65
|
+
json(message: "Welcome #{params.name}")
|
66
|
+
else
|
67
|
+
json(404, error: "not found")
|
68
|
+
end
|
60
69
|
end
|
61
70
|
end
|
62
|
-
|
63
|
-
# You can setup any Rack Middleware
|
64
|
-
|
65
|
-
FitApi.use Rack::CommonLogger, Logger.new('log/app.log')
|
66
|
-
|
67
|
-
Rack::Handler::WEBrick.run FitApi.app
|
68
71
|
```
|
69
72
|
|
70
73
|
```bash
|
71
|
-
|
74
|
+
rackup
|
72
75
|
```
|
73
76
|
|
74
77
|
## Router
|
75
78
|
|
76
|
-
It recognizes URLs and invoke the controller
|
79
|
+
It recognizes URLs and invoke the controller"s action... the DSL is pretty similar to Rails (obviously not so powerful):
|
77
80
|
|
78
81
|
### HTTP methods:
|
79
82
|
|
80
83
|
```ruby
|
81
|
-
get
|
82
|
-
post
|
83
|
-
put
|
84
|
-
delete
|
84
|
+
get "/test/:name", to: "app#test_show"
|
85
|
+
post "/test", to: "app#test_post"
|
86
|
+
put "/test", to: "app#test_put"
|
87
|
+
delete "/test/:id", to: "app#test_delete"
|
85
88
|
```
|
86
89
|
|
87
90
|
----
|
88
91
|
|
89
92
|
### Resources
|
90
93
|
|
91
|
-
You can pass the following options:
|
92
|
-
|
93
|
-
```
|
94
|
-
only
|
95
|
-
except
|
96
|
-
controller
|
94
|
+
You can pass the following options: `only, except, controller`
|
97
95
|
```
|
98
96
|
|
99
97
|
**Nested:**
|
@@ -133,7 +131,7 @@ end
|
|
133
131
|
**Member & Collection:**
|
134
132
|
|
135
133
|
```ruby
|
136
|
-
resources :contacts, only:
|
134
|
+
resources :contacts, only: :index do
|
137
135
|
member do
|
138
136
|
post :add_activity
|
139
137
|
end
|
@@ -171,14 +169,14 @@ end
|
|
171
169
|
-----
|
172
170
|
|
173
171
|
```ruby
|
174
|
-
namespace
|
172
|
+
namespace "/hello/world", controller: :test do
|
175
173
|
get :test
|
176
174
|
end
|
177
175
|
```
|
178
176
|
|
179
177
|
| Method | Path | Controller & action |
|
180
178
|
|----------|-------------------|-----------------------|
|
181
|
-
| **GET** | /
|
179
|
+
| **GET** | /hello/world/test | test#test |
|
182
180
|
|
183
181
|
-----
|
184
182
|
|
@@ -187,7 +185,7 @@ end
|
|
187
185
|
```ruby
|
188
186
|
controller :app do
|
189
187
|
get :another_action
|
190
|
-
get
|
188
|
+
get "/welcome", action: "hello_world"
|
191
189
|
end
|
192
190
|
```
|
193
191
|
|
@@ -201,7 +199,7 @@ end
|
|
201
199
|
### Root
|
202
200
|
|
203
201
|
```ruby
|
204
|
-
root to:
|
202
|
+
root to: "app#index"
|
205
203
|
```
|
206
204
|
|
207
205
|
| Method | Path | Controller & action |
|
@@ -213,7 +211,7 @@ root to: 'app#index'
|
|
213
211
|
### Customize error 404 message
|
214
212
|
|
215
213
|
```ruby
|
216
|
-
not_found to:
|
214
|
+
not_found to: "app#error_404"
|
217
215
|
```
|
218
216
|
|
219
217
|
## Controllers
|
@@ -224,17 +222,15 @@ One limitation is the class name of your controller must end with "Controller",
|
|
224
222
|
```ruby
|
225
223
|
class AppController < FitApi::Controller
|
226
224
|
def index
|
227
|
-
json
|
225
|
+
json "hello world"
|
228
226
|
end
|
229
227
|
|
230
|
-
def
|
231
|
-
json
|
228
|
+
def create
|
229
|
+
json 201, resource
|
232
230
|
end
|
233
231
|
end
|
234
232
|
```
|
235
233
|
|
236
|
-
You have the method `#json` available, which basically sets the response body.
|
237
|
-
|
238
234
|
Default status code: ```200```
|
239
235
|
|
240
236
|
----
|
@@ -254,8 +250,8 @@ You can exit the current action throwing an exception... the default status code
|
|
254
250
|
```ruby
|
255
251
|
halt
|
256
252
|
halt 500
|
257
|
-
halt 404,
|
258
|
-
halt
|
253
|
+
halt 404, "Not found"
|
254
|
+
halt "Error message"
|
259
255
|
```
|
260
256
|
|
261
257
|
----
|
@@ -265,33 +261,33 @@ halt 'Error message'
|
|
265
261
|
#### GET /users
|
266
262
|
|
267
263
|
```bash
|
268
|
-
curl -i http://localhost:1337/users/:id?name=Berna&
|
264
|
+
curl -i http://localhost:1337/users/:id?name=Berna&level=1&xp=70
|
269
265
|
```
|
270
266
|
|
271
267
|
```ruby
|
272
268
|
params.id # 1
|
273
269
|
params.name # "Berna"
|
274
|
-
params[:
|
275
|
-
params[
|
270
|
+
params[:level] # 1
|
271
|
+
params["xp"] # 70
|
276
272
|
```
|
277
273
|
|
278
274
|
#### POST with params:
|
279
275
|
|
280
276
|
```bash
|
281
|
-
curl -i -X POST -d
|
277
|
+
curl -i -X POST -d "user[name]=Berna&user[level]=1" http://localhost:1337/users
|
282
278
|
```
|
283
279
|
|
284
280
|
#### POST with JSON:
|
285
281
|
|
286
282
|
```bash
|
287
|
-
curl -i -X POST -H "Content-Type: application/json" -d
|
283
|
+
curl -i -X POST -H "Content-Type: application/json" -d "{ "user": { "name": "Berna", "xp": 50 } }" http://localhost:1337/users
|
288
284
|
```
|
289
285
|
|
290
286
|
Result:
|
291
287
|
|
292
288
|
```ruby
|
293
289
|
params.user.name # "Berna"
|
294
|
-
params[:user][:
|
290
|
+
params[:user][:xp] # 50
|
295
291
|
```
|
296
292
|
|
297
293
|
----
|
@@ -299,7 +295,7 @@ params[:user][:age] # "28"
|
|
299
295
|
#### #permit
|
300
296
|
|
301
297
|
```ruby
|
302
|
-
params.user.permit(:name, :
|
298
|
+
params.user.permit(:name, :level, :xp)
|
303
299
|
```
|
304
300
|
|
305
301
|
----
|
@@ -315,7 +311,7 @@ params.user.except(:height)
|
|
315
311
|
### Request Headers
|
316
312
|
|
317
313
|
```ruby
|
318
|
-
request.headers[
|
314
|
+
request.headers["Authorization"]
|
319
315
|
```
|
320
316
|
|
321
317
|
----
|
@@ -323,7 +319,7 @@ request.headers['Authorization']
|
|
323
319
|
### Response Headers
|
324
320
|
|
325
321
|
```ruby
|
326
|
-
headers[
|
322
|
+
headers["Header-Name"] = "Header Value"
|
327
323
|
```
|
328
324
|
|
329
325
|
----
|
@@ -332,7 +328,7 @@ headers['Header-Name'] = 'Header Value'
|
|
332
328
|
|
333
329
|
```ruby
|
334
330
|
before_action *actions, only: %i(index show)
|
335
|
-
after_action *actions, except:
|
331
|
+
after_action *actions, except: :destroy
|
336
332
|
```
|
337
333
|
|
338
334
|
## TODO:
|
data/lib/fit_api.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
require 'json/ext'
|
3
|
-
require 'dry/inflector'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
3
|
+
require "rack"
|
4
|
+
require "json/ext"
|
5
|
+
require "dry/inflector"
|
6
|
+
|
7
|
+
require "fit_api/version"
|
8
|
+
require "fit_api/router"
|
9
|
+
require "fit_api/controller"
|
8
10
|
|
9
11
|
module FitApi
|
10
12
|
def self.builder
|
data/lib/fit_api/controller.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FitApi
|
2
4
|
class Halt < StandardError; end
|
3
5
|
|
4
6
|
class Controller
|
5
|
-
attr_accessor :response
|
7
|
+
attr_accessor :response, :action
|
6
8
|
attr_reader :request, :params, :headers
|
7
9
|
|
8
10
|
def initialize(request, params)
|
9
11
|
@request = request
|
10
12
|
@params = params
|
11
|
-
|
13
|
+
|
14
|
+
set_default_headers
|
15
|
+
|
16
|
+
@response = [ 501, @headers, [ 'Not implemented' ] ]
|
12
17
|
end
|
13
18
|
|
14
19
|
class << self
|
@@ -18,35 +23,65 @@ module FitApi
|
|
18
23
|
|
19
24
|
%i(before after).each do |callback_type|
|
20
25
|
define_method "#{callback_type}_action" do |*callbacks|
|
21
|
-
|
26
|
+
options = callbacks.last.is_a?(Hash) ? callbacks.last : {}
|
22
27
|
|
23
28
|
callbacks.each do |method|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
29
|
+
next if method.is_a?(Hash)
|
30
|
+
actions[callback_type] << { method: method }.merge(options)
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
headers.each &response.method(:add_header)
|
37
|
-
end
|
38
|
-
|
39
|
-
def json(object, status = 200)
|
40
|
-
self.response = Rack::Response.new(JSON.pretty_generate(object), status)
|
36
|
+
def json(status = 200, data)
|
37
|
+
data = data.to_h unless data.is_a?(Hash) && data.is_a?(String)
|
38
|
+
json = JSON.pretty_generate(data)
|
39
|
+
@response = [ status, headers, [ json ] ]
|
41
40
|
end
|
42
41
|
|
43
42
|
def halt(*args)
|
44
43
|
is_int = args.first.is_a?(Integer)
|
45
44
|
status = is_int ? args.first : 400
|
46
|
-
error = is_int ? (args.count > 1 ? args.last :
|
45
|
+
error = is_int ? (args.count > 1 ? args.last : "") : args.first
|
47
46
|
|
48
|
-
json(
|
47
|
+
json(status, error.to_h)
|
49
48
|
raise Halt
|
50
49
|
end
|
50
|
+
|
51
|
+
def invoke(action)
|
52
|
+
return unless respond_to?(action)
|
53
|
+
self.action = action.to_sym
|
54
|
+
trigger_callbacks(:before, action)
|
55
|
+
send(action)
|
56
|
+
trigger_callbacks(:after, action)
|
57
|
+
@response
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def set_default_headers
|
63
|
+
@headers = {
|
64
|
+
"Date" => Rack::Utils.rfc2822(Time.now),
|
65
|
+
"Content-Type" => "application/json"
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def trigger_callbacks(type, action)
|
70
|
+
klass = self.class
|
71
|
+
while klass != Object
|
72
|
+
actions = klass.actions[type].each do |rule|
|
73
|
+
send(rule[:method]) if run?(rule, action.to_sym)
|
74
|
+
end
|
75
|
+
klass = klass.superclass
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def run?(rule, action)
|
80
|
+
except, only = Array(rule[:except]), Array(rule[:only])
|
81
|
+
|
82
|
+
except.any? && !except.include?(action) ||
|
83
|
+
only.any? && only.include?(action) ||
|
84
|
+
only.empty? && except.empty?
|
85
|
+
end
|
51
86
|
end
|
52
87
|
end
|
data/lib/fit_api/router.rb
CHANGED
@@ -1,36 +1,45 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fit_api/router/mapper"
|
2
4
|
|
3
5
|
module FitApi
|
4
6
|
module Router
|
5
|
-
|
6
|
-
method, path = env['REQUEST_METHOD'], env['PATH_INFO']
|
7
|
-
is_root = path == '/'
|
7
|
+
module_function
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
status = is_root ? 200 : 404
|
13
|
-
res = is_root ? 'fit-api is working!' : 'Action not found'
|
9
|
+
def call(env)
|
10
|
+
method, path = env["REQUEST_METHOD"], env["PATH_INFO"]
|
11
|
+
is_root = path == "/"
|
14
12
|
|
15
|
-
|
13
|
+
if route = find(method, path, !is_root)
|
14
|
+
return route.invoke(env)
|
16
15
|
end
|
16
|
+
|
17
|
+
status = is_root ? 200 : 404
|
18
|
+
res = is_root ? "fit-api is working!" : "Action not found"
|
19
|
+
|
20
|
+
[ status, { "Content-Type" => "application/json" }, [ res.to_json ] ]
|
17
21
|
end
|
18
22
|
|
19
|
-
def
|
23
|
+
def find(method, path, fetch_not_found = true)
|
20
24
|
route = mapper.routes[method.downcase].find { |route| route.match? path }
|
21
25
|
return route if route
|
22
26
|
|
23
|
-
if
|
24
|
-
not_found = find(
|
27
|
+
if fetch_not_found
|
28
|
+
not_found = find("get", "/404", false)
|
25
29
|
return not_found if not_found
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
29
|
-
def
|
33
|
+
def auto_load_path(path = nil)
|
34
|
+
return @auto_load_path unless path
|
35
|
+
@auto_load_path = path
|
36
|
+
end
|
37
|
+
|
38
|
+
def define(&block)
|
30
39
|
mapper.instance_eval &block
|
31
40
|
end
|
32
41
|
|
33
|
-
def
|
42
|
+
def mapper
|
34
43
|
@mapper ||= Mapper.new
|
35
44
|
end
|
36
45
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fit_api/router/route"
|
2
4
|
|
3
5
|
module FitApi
|
4
6
|
module Router
|
@@ -13,6 +15,7 @@ module FitApi
|
|
13
15
|
%w(get post put delete patch).each do |verb|
|
14
16
|
define_method verb do |path, options = {}|
|
15
17
|
options[:controller] ||= @controller
|
18
|
+
|
16
19
|
route = Route.new(verb, "#{@namespaces.join}#{fix_path(path)}", options)
|
17
20
|
@routes[verb] << route
|
18
21
|
end
|
@@ -25,15 +28,15 @@ module FitApi
|
|
25
28
|
end
|
26
29
|
|
27
30
|
def root(to:)
|
28
|
-
get
|
31
|
+
get "", to: to
|
29
32
|
end
|
30
33
|
|
31
34
|
def not_found(to:)
|
32
|
-
get
|
35
|
+
get "/404", to: to
|
33
36
|
end
|
34
37
|
|
35
38
|
def member(&block)
|
36
|
-
namespace
|
39
|
+
namespace "/:id", controller: @controller, &block
|
37
40
|
end
|
38
41
|
|
39
42
|
def collection(&block)
|
@@ -79,8 +82,8 @@ module FitApi
|
|
79
82
|
only = options[:only]
|
80
83
|
except = options[:except]
|
81
84
|
|
82
|
-
return actions & only if only
|
83
|
-
return actions - except if except
|
85
|
+
return actions & Array(only) if only
|
86
|
+
return actions - Array(except) if except
|
84
87
|
|
85
88
|
actions
|
86
89
|
end
|
@@ -93,9 +96,9 @@ module FitApi
|
|
93
96
|
actions.each do |action|
|
94
97
|
case action
|
95
98
|
when :index
|
96
|
-
get
|
99
|
+
get "", to: "#{resource}#index"
|
97
100
|
when :create
|
98
|
-
post
|
101
|
+
post "", to: "#{resource}#create"
|
99
102
|
when :show
|
100
103
|
get path, to: "#{resource}#show"
|
101
104
|
when :update
|
@@ -118,13 +121,13 @@ module FitApi
|
|
118
121
|
end
|
119
122
|
|
120
123
|
def get_resource_path(type)
|
121
|
-
return type == :resources ?
|
124
|
+
return type == :resources ? "/:id" : ""
|
122
125
|
end
|
123
126
|
|
124
127
|
def fix_path(path)
|
125
|
-
fix = path.is_a?(Symbol) || path[0] !=
|
128
|
+
fix = path.is_a?(Symbol) || path[0] != "/" && path != ""
|
126
129
|
path = fix ? "/#{path}" : path
|
127
|
-
path.gsub(/\/$/,
|
130
|
+
path.gsub(/\/$/, "")
|
128
131
|
end
|
129
132
|
|
130
133
|
def s(word)
|
@@ -1,54 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FitApi
|
2
4
|
module Router
|
3
|
-
|
4
|
-
def initialize(hash)
|
5
|
-
@hash = hash
|
6
|
-
end
|
7
|
-
|
8
|
-
def to_h
|
9
|
-
@hash
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_json
|
13
|
-
@hash.to_json
|
14
|
-
end
|
15
|
-
|
5
|
+
module Params
|
16
6
|
def [](key)
|
17
|
-
value =
|
18
|
-
|
7
|
+
value = super(key.to_s)
|
19
8
|
if value.is_a?(Hash)
|
20
|
-
|
21
|
-
else
|
22
|
-
value
|
9
|
+
value.extend(Params)
|
23
10
|
end
|
11
|
+
value
|
24
12
|
end
|
25
13
|
|
26
|
-
def
|
27
|
-
|
14
|
+
def except(*blacklist)
|
15
|
+
blacklist.map!(&:to_s)
|
16
|
+
build(keys - blacklist)
|
28
17
|
end
|
29
18
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
nil
|
35
|
-
end
|
19
|
+
def permit(*whitelist)
|
20
|
+
whitelist.map!(&:to_s)
|
21
|
+
build(keys & whitelist)
|
36
22
|
end
|
37
23
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
)
|
24
|
+
private
|
25
|
+
|
26
|
+
def build(new_keys)
|
27
|
+
{}.tap do |h|
|
28
|
+
new_keys.each { |k| h[k] = self[k] }
|
29
|
+
end.extend(Params)
|
44
30
|
end
|
45
31
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
(@hash.keys & whitelist.map(&:to_s)).each { |k| h[k] = @hash[k] }
|
50
|
-
end
|
51
|
-
)
|
32
|
+
def method_missing(method_sym, *args, &block)
|
33
|
+
attr = self.key?(method_sym) ? method_sym : method_sym.to_s
|
34
|
+
self[attr]
|
52
35
|
end
|
53
36
|
end
|
54
37
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FitApi
|
2
4
|
module Router
|
3
5
|
class Parser
|
@@ -5,7 +7,7 @@ module FitApi
|
|
5
7
|
|
6
8
|
def initialize(route, path)
|
7
9
|
@route = route
|
8
|
-
@path = path.gsub(/\/$/,
|
10
|
+
@path = path.gsub(/\/$/, "")
|
9
11
|
@match = false
|
10
12
|
@params = {}
|
11
13
|
|
@@ -29,12 +31,12 @@ module FitApi
|
|
29
31
|
|
30
32
|
params.each_index do |i|
|
31
33
|
@params[params[i]] =
|
32
|
-
result[i].match(/^\d+$/) ? result[i].to_i : URI.
|
34
|
+
result[i].match(/^\d+$/) ? result[i].to_i : URI.decode_www_form_component(result[i])
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
def regexp
|
37
|
-
@route.gsub(/\:\w+/,
|
39
|
+
@route.gsub(/\:\w+/, "([^\/]*)")
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
data/lib/fit_api/router/route.rb
CHANGED
@@ -1,87 +1,68 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fit_api/router/parser"
|
4
|
+
require "fit_api/router/params"
|
3
5
|
|
4
6
|
module FitApi
|
5
7
|
module Router
|
6
|
-
class
|
7
|
-
|
8
|
+
class Request < Rack::Request
|
9
|
+
def headers
|
10
|
+
env.select { |k,v| k.start_with? "HTTP_"}.
|
11
|
+
transform_keys { |k| k.sub(/^HTTP_/, "").split("_").map(&:capitalize).join("-") }
|
12
|
+
end
|
13
|
+
end
|
8
14
|
|
15
|
+
class Route
|
9
16
|
def initialize(verb, path, options = {})
|
10
17
|
@verb = verb
|
11
18
|
@path = path
|
12
19
|
@controller = get_controller(options)
|
13
20
|
@action = get_action(options)
|
21
|
+
|
22
|
+
require_controller
|
14
23
|
end
|
15
24
|
|
16
25
|
def invoke(env)
|
17
|
-
request
|
18
|
-
|
19
|
-
|
20
|
-
params = Params.new(request.params.merge(route_params).merge(json_params))
|
21
|
-
controller = Object.const_get("#{@controller.to_s.capitalize}Controller").new(request, params)
|
26
|
+
request = Request.new(env)
|
27
|
+
params = build_params(request)
|
28
|
+
controller = Object.const_get("#{@controller.to_s.capitalize}Controller").new(request, params)
|
22
29
|
|
23
|
-
|
30
|
+
controller.invoke(@action)
|
24
31
|
rescue Halt
|
25
|
-
controller.set_response_headers
|
26
32
|
controller.response
|
27
|
-
rescue Exception => ex
|
28
|
-
error = { message: "#{ex.message} (#{ex.class})", backtrace: ex.backtrace }
|
29
|
-
controller.json(ENV['RACK_ENV'] == 'production' ? 'An error has occured' : error, 500)
|
30
33
|
end
|
31
34
|
|
32
35
|
def match?(path)
|
33
|
-
|
36
|
+
Parser.new(@path, path).match?
|
34
37
|
end
|
35
38
|
|
36
39
|
private
|
37
40
|
|
38
41
|
def get_controller(options)
|
39
42
|
return options[:controller] if options[:controller]
|
40
|
-
options[:to].split(
|
43
|
+
options[:to].split("#").first
|
41
44
|
end
|
42
45
|
|
43
46
|
def get_action(options)
|
44
47
|
return options[:action] if options[:action]
|
45
|
-
return options[:to].split(
|
46
|
-
path[/\w+$/]
|
47
|
-
end
|
48
|
-
|
49
|
-
def parse(path)
|
50
|
-
Parser.new(@path, path)
|
48
|
+
return options[:to].split("#").last if options[:to]
|
49
|
+
@path[/\w+$/]
|
51
50
|
end
|
52
51
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
run_callbacks! controller, :after
|
57
|
-
controller.set_response_headers
|
58
|
-
controller.response
|
59
|
-
end
|
60
|
-
|
61
|
-
def run_callbacks!(controller, type)
|
62
|
-
klass = controller.class
|
63
|
-
|
64
|
-
while klass != Object
|
65
|
-
actions = klass.actions[type].each do |rule|
|
66
|
-
controller.send(rule[:method]) if run?(rule)
|
67
|
-
end
|
68
|
-
klass = klass.superclass
|
52
|
+
def require_controller
|
53
|
+
if path = Router.auto_load_path
|
54
|
+
require "./#{path}/#{@controller}_controller"
|
69
55
|
end
|
70
56
|
end
|
71
57
|
|
72
|
-
def
|
73
|
-
|
58
|
+
def build_params(request)
|
59
|
+
route_params = Parser.new(@path, request.path).params
|
60
|
+
params = JSON.parse(request.body.read) rescue request.params
|
74
61
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
class Request < Rack::Request
|
82
|
-
def headers
|
83
|
-
env.select { |k,v| k.start_with? 'HTTP_'}.
|
84
|
-
transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }
|
62
|
+
new_params = params.merge(route_params)
|
63
|
+
new_params.extend(Params)
|
64
|
+
new_params.with_indifferent_access
|
65
|
+
new_params
|
85
66
|
end
|
86
67
|
end
|
87
68
|
end
|
data/lib/fit_api/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fit_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernardo Castro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -78,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
78
|
version: '0'
|
79
79
|
requirements: []
|
80
80
|
rubyforge_project:
|
81
|
-
rubygems_version: 2.
|
81
|
+
rubygems_version: 2.6.13
|
82
82
|
signing_key:
|
83
83
|
specification_version: 4
|
84
84
|
summary: Lightweight framework for building APIs
|