fit_api 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +76 -55
- data/lib/fit_api/controller.rb +7 -5
- data/lib/fit_api/router/mapper.rb +8 -8
- data/lib/fit_api/router/route.rb +1 -1
- data/lib/fit_api/router.rb +10 -7
- data/lib/fit_api/version.rb +3 -1
- data/lib/fit_api.rb +15 -1
- metadata +2 -3
- data/lib/fit_api/app.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9625dc724aa00c2091520f8a00037e2a0deb289ff46a0531c21c45ad0d70a44e
|
4
|
+
data.tar.gz: 2270242c3c7afadaa86162c580c8b1d042e5a64a5a65807205c15b5b78e2ba67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3985a5d07c254aef0abd05e8e67d91d49fab2eae6c11d83a5636eca8e610f42d5a2b6b6868ab6b4bdb5f11f7b2e702c49a00509a1ee8f562790d98221752ac8b
|
7
|
+
data.tar.gz: 1a2c24f461c00ae5b78a3bef8c47fa3ded025ed567088f1c16f55ba179277e03078642bfc3ca3afc5287ba9a0285909ea2f774d93bc589db67c5b86bc2f56aca
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -4,8 +4,8 @@ Lightweight framework for building JSON API's
|
|
4
4
|
|
5
5
|
## Introduction
|
6
6
|
|
7
|
-
fit-api is a
|
8
|
-
The goal of this
|
7
|
+
fit-api is a library based on Rack and inspired by Rails & Sinatra.
|
8
|
+
The goal of this gem is to provide simplicity when developing an API with ruby.
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
@@ -28,41 +28,28 @@ $ gem install fit_api
|
|
28
28
|
* [404](#customize-error-404-message)
|
29
29
|
* [Controllers](#controllers)
|
30
30
|
* [Request](#request)
|
31
|
+
* [Halt](#halt)
|
31
32
|
* [Params](#params)
|
32
33
|
* [Headers](#request-headers)
|
33
34
|
* [Callbacks](#callbacks)
|
34
|
-
* [Rack Middlewares](#rack-middlewares)
|
35
35
|
|
36
36
|
|
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](/bermanya/fit-api-demo)
|
40
|
+
[fit-api-demo](http://github.com/bermanya/fit-api-demo)
|
41
41
|
|
42
|
-
**
|
42
|
+
**api.rb**
|
43
43
|
|
44
44
|
```ruby
|
45
45
|
require 'fit_api'
|
46
46
|
|
47
|
-
require_relative 'routes'
|
48
|
-
require_relative 'app_controller'
|
49
|
-
|
50
|
-
Rack::Handler::WEBrick.run FitApi::App.new
|
51
|
-
```
|
52
|
-
|
53
|
-
**routes.rb**
|
54
|
-
|
55
|
-
```ruby
|
56
47
|
FitApi::Router.define do
|
57
48
|
get '/:name', to: 'app#show'
|
58
49
|
|
59
50
|
root to: 'app#index'
|
60
51
|
end
|
61
|
-
```
|
62
52
|
|
63
|
-
**app_controller.rb**
|
64
|
-
|
65
|
-
```ruby
|
66
53
|
class AppController < FitApi::Controller
|
67
54
|
def index
|
68
55
|
json({ message: 'Hello world' })
|
@@ -72,15 +59,21 @@ class AppController < FitApi::Controller
|
|
72
59
|
json({ message: "Welcome #{params.name}" })
|
73
60
|
end
|
74
61
|
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
|
75
68
|
```
|
76
69
|
|
77
70
|
```bash
|
78
|
-
ruby
|
71
|
+
ruby api.rb
|
79
72
|
```
|
80
73
|
|
81
74
|
## Router
|
82
75
|
|
83
|
-
It recognizes URLs and invoke the controller's action... the DSL is pretty similar to Rails (obviously not
|
76
|
+
It recognizes URLs and invoke the controller's action... the DSL is pretty similar to Rails (obviously not so powerful):
|
84
77
|
|
85
78
|
### HTTP methods:
|
86
79
|
|
@@ -91,6 +84,8 @@ put '/test', to: 'app#test_put'
|
|
91
84
|
delete '/test/:id', to: 'app#test_delete'
|
92
85
|
```
|
93
86
|
|
87
|
+
----
|
88
|
+
|
94
89
|
### Resources
|
95
90
|
|
96
91
|
**Nested:**
|
@@ -208,12 +203,12 @@ root to: 'app#index'
|
|
208
203
|
### Customize error 404 message
|
209
204
|
|
210
205
|
```ruby
|
211
|
-
not_found 'app#error_404'
|
206
|
+
not_found to: 'app#error_404'
|
212
207
|
```
|
213
208
|
|
214
209
|
## Controllers
|
215
210
|
|
216
|
-
The library provides one
|
211
|
+
The library provides one class `FitApi::Controller` which should be inherited from your controllers.
|
217
212
|
One limitation is the class name of your controller must end with "Controller", i.e: AppController, UsersController...
|
218
213
|
|
219
214
|
```ruby
|
@@ -228,82 +223,108 @@ class AppController < FitApi::Controller
|
|
228
223
|
end
|
229
224
|
```
|
230
225
|
|
231
|
-
You have the method `#json` available, basically
|
226
|
+
You have the method `#json` available, which basically sets the response body.
|
227
|
+
|
228
|
+
----
|
232
229
|
|
233
230
|
### Request
|
234
231
|
|
235
|
-
You can access the Request object like this:
|
232
|
+
You can access the Request object like this:
|
236
233
|
|
237
|
-
|
234
|
+
`request`
|
238
235
|
|
239
|
-
|
236
|
+
----
|
240
237
|
|
241
|
-
|
238
|
+
### Halt
|
239
|
+
|
240
|
+
You can exit the current action throwing an exception... the default status code is 400
|
242
241
|
|
243
242
|
```ruby
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
243
|
+
halt
|
244
|
+
halt 500
|
245
|
+
halt 404, 'Not found'
|
246
|
+
halt 'Error message'
|
248
247
|
```
|
249
248
|
|
250
|
-
|
249
|
+
----
|
250
|
+
|
251
|
+
### Params
|
251
252
|
|
252
|
-
|
253
|
+
#### GET /users
|
253
254
|
|
254
255
|
```bash
|
255
|
-
curl -i
|
256
|
+
curl -i http://localhost:1337/users/:id?name=Berna&age=28&height=180
|
256
257
|
```
|
257
258
|
|
258
|
-
|
259
|
+
```ruby
|
260
|
+
params.id # 1
|
261
|
+
params.name # "Berna"
|
262
|
+
params[:age] # 28
|
263
|
+
params['height'] # 180
|
264
|
+
```
|
265
|
+
|
266
|
+
#### POST with params:
|
259
267
|
|
260
268
|
```bash
|
261
|
-
curl -i -X POST
|
269
|
+
curl -i -X POST -d 'user[name]=Berna&user[age]=28' http://localhost:1337/users
|
262
270
|
```
|
263
271
|
|
264
|
-
|
272
|
+
#### POST with JSON:
|
265
273
|
|
266
|
-
```
|
267
|
-
|
268
|
-
params.user.name # "Berna"
|
269
|
-
params[:user][:age] # 28
|
274
|
+
```bash
|
275
|
+
curl -i -X POST -H "Content-Type: application/json" -d '{ "user": { "name": "Berna", "age": 28 } }' http://localhost:1337/users
|
270
276
|
```
|
271
277
|
|
272
|
-
|
278
|
+
Result:
|
273
279
|
|
274
280
|
```ruby
|
275
|
-
|
281
|
+
params.user.name # "Berna"
|
282
|
+
params[:user][:age] # "28"
|
276
283
|
```
|
277
284
|
|
278
|
-
|
285
|
+
----
|
286
|
+
|
287
|
+
#### #permit
|
279
288
|
|
280
289
|
```ruby
|
281
|
-
|
290
|
+
params.user.permit(:name, :age)
|
282
291
|
```
|
283
292
|
|
284
|
-
|
293
|
+
----
|
294
|
+
|
295
|
+
#### #except
|
285
296
|
|
286
297
|
```ruby
|
287
|
-
|
288
|
-
after_action *actions, only: %i(index show)
|
298
|
+
params.user.except(:height)
|
289
299
|
```
|
290
300
|
|
291
|
-
|
301
|
+
----
|
302
|
+
|
303
|
+
### Request Headers
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
request.headers['Authorization']
|
307
|
+
```
|
292
308
|
|
293
|
-
|
309
|
+
----
|
294
310
|
|
295
|
-
|
311
|
+
### Response Headers
|
296
312
|
|
297
313
|
```ruby
|
298
|
-
|
314
|
+
headers['Header-Name'] = 'Header Value'
|
315
|
+
```
|
299
316
|
|
300
|
-
|
317
|
+
----
|
301
318
|
|
302
|
-
|
319
|
+
### Callbacks
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
before_action *actions
|
323
|
+
after_action *actions, only: %i(index show)
|
303
324
|
```
|
304
325
|
|
305
326
|
## TODO:
|
306
327
|
- [ ] Implement tests
|
307
328
|
- [ ] Allow websockets -> `FitApi::Controller#stream`
|
308
329
|
|
309
|
-
Any contribution would be appreciated =)
|
330
|
+
Any contribution would be appreciated =)
|
data/lib/fit_api/controller.rb
CHANGED
@@ -29,8 +29,8 @@ module FitApi
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def set_response_headers
|
32
|
-
|
33
|
-
|
32
|
+
headers['Date'] = Rack::Utils.rfc2822(Time.now)
|
33
|
+
headers['Content-Type'] = 'application/json'
|
34
34
|
|
35
35
|
headers.each &response.method(:add_header)
|
36
36
|
end
|
@@ -38,11 +38,13 @@ module FitApi
|
|
38
38
|
private
|
39
39
|
|
40
40
|
def json(hash, status: 200)
|
41
|
-
self.response =
|
42
|
-
Rack::Response.new(hash.to_json, status)
|
41
|
+
self.response = Rack::Response.new(hash.to_json, status)
|
43
42
|
end
|
44
43
|
|
45
|
-
def halt(
|
44
|
+
def halt(*args)
|
45
|
+
is_integer = args.first.is_a?(Integer)
|
46
|
+
status = is_integer ? args.first : 400
|
47
|
+
error = is_integer ? (args.count > 1 ? args.last : '') : args.first
|
46
48
|
json(error, status: status)
|
47
49
|
raise Halt
|
48
50
|
end
|
@@ -28,7 +28,7 @@ module FitApi
|
|
28
28
|
get '', to: to
|
29
29
|
end
|
30
30
|
|
31
|
-
def not_found(to)
|
31
|
+
def not_found(to:)
|
32
32
|
get '/404', to: to
|
33
33
|
end
|
34
34
|
|
@@ -60,10 +60,12 @@ module FitApi
|
|
60
60
|
|
61
61
|
def set_resource(type, resource, options, &block)
|
62
62
|
options[:only] ||= %i(index show create update destroy)
|
63
|
+
options[:controller] ||= resource
|
64
|
+
|
63
65
|
path = get_path(type, resource)
|
64
66
|
|
65
67
|
@parent = [ type, resource ]
|
66
|
-
@controller = options[:controller]
|
68
|
+
@controller = options[:controller]
|
67
69
|
|
68
70
|
namespace path, options do
|
69
71
|
set_actions type, resource, options[:only]
|
@@ -97,7 +99,7 @@ module FitApi
|
|
97
99
|
def get_path(type, resource)
|
98
100
|
return "/:#{s(@parent.last)}_id/#{resource}" if type == :resources && parent_is?(:resources)
|
99
101
|
return "/:#{s(@parent.last)}_id/#{s(resource)}" if type == :resource && parent_is?(:resources)
|
100
|
-
return "/#{s(resource)}"
|
102
|
+
return "/#{s(resource)}" if type == :resource && parent_is?(:resource)
|
101
103
|
return "/#{resource}"
|
102
104
|
end
|
103
105
|
|
@@ -110,11 +112,9 @@ module FitApi
|
|
110
112
|
end
|
111
113
|
|
112
114
|
def fix_path(path)
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
path
|
117
|
-
end
|
115
|
+
fix = path.is_a?(Symbol) || path[0] != '/' && path != ''
|
116
|
+
path = fix ? "/#{path}" : path
|
117
|
+
path.gsub(/\/$/, '')
|
118
118
|
end
|
119
119
|
|
120
120
|
def s(word)
|
data/lib/fit_api/router/route.rb
CHANGED
@@ -18,7 +18,7 @@ module FitApi
|
|
18
18
|
route_params = parse(request.path).params
|
19
19
|
json_params = JSON.parse(request.body.read) rescue {}
|
20
20
|
params = Params.new(request.params.merge(route_params).merge(json_params))
|
21
|
-
controller = Object.const_get("#{@controller.capitalize}Controller").new(request, params)
|
21
|
+
controller = Object.const_get("#{@controller.to_s.capitalize}Controller").new(request, params)
|
22
22
|
|
23
23
|
run! controller
|
24
24
|
rescue Halt
|
data/lib/fit_api/router.rb
CHANGED
@@ -4,22 +4,25 @@ module FitApi
|
|
4
4
|
module Router
|
5
5
|
def self.call(env)
|
6
6
|
method, path = env['REQUEST_METHOD'], env['PATH_INFO']
|
7
|
-
|
7
|
+
is_root = path == '/'
|
8
8
|
|
9
|
-
|
9
|
+
if route = Router.find(method, path, !is_root)
|
10
|
+
route.invoke(env)
|
11
|
+
else
|
12
|
+
status = is_root ? 200 : 404
|
13
|
+
res = is_root ? 'fit-api is working!' : 'Action not found'
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
[ res[:error] ? 404 : 200, { 'Content-Type' => 'application/json'}, [ res.to_json ] ]
|
15
|
+
[ status, { 'Content-Type' => 'application/json'}, [ res.to_json ] ]
|
16
|
+
end
|
14
17
|
end
|
15
18
|
|
16
|
-
def self.find(method, path,
|
19
|
+
def self.find(method, path, find_not_found_action = true)
|
17
20
|
routes = mapper.routes[method.downcase]
|
18
21
|
route = routes.find { |route| route.match? path }
|
19
22
|
|
20
23
|
return route if route
|
21
24
|
|
22
|
-
if
|
25
|
+
if find_not_found_action
|
23
26
|
not_found = find('get', '/404', false)
|
24
27
|
return not_found if not_found
|
25
28
|
end
|
data/lib/fit_api/version.rb
CHANGED
data/lib/fit_api.rb
CHANGED
@@ -2,10 +2,24 @@ require 'rack'
|
|
2
2
|
require 'json/ext'
|
3
3
|
require 'dry/inflector'
|
4
4
|
|
5
|
-
require 'fit_api/
|
5
|
+
require 'fit_api/version'
|
6
|
+
require 'fit_api/router'
|
6
7
|
require 'fit_api/controller'
|
7
8
|
|
8
9
|
module FitApi
|
10
|
+
def self.builder
|
11
|
+
@builder ||= Rack::Builder.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.use(middleware, *args, &block)
|
15
|
+
builder.use(middleware, *args, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.app
|
19
|
+
builder.run Router.method(:call)
|
20
|
+
builder.to_app
|
21
|
+
end
|
22
|
+
|
9
23
|
def self.inflector
|
10
24
|
@inflector ||= Dry::Inflector.new
|
11
25
|
end
|
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.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernardo Castro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -51,7 +51,6 @@ files:
|
|
51
51
|
- Rakefile
|
52
52
|
- fit_api.gemspec
|
53
53
|
- lib/fit_api.rb
|
54
|
-
- lib/fit_api/app.rb
|
55
54
|
- lib/fit_api/controller.rb
|
56
55
|
- lib/fit_api/router.rb
|
57
56
|
- lib/fit_api/router/mapper.rb
|