fit_api 1.0.1 → 1.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 +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
|