rack-kibo 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/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +112 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rack/kibo.rb +2 -0
- data/lib/rack/kibo/kibo.rb +163 -0
- data/lib/rack/kibo/version.rb +5 -0
- data/rack-kibo.gemspec +33 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b982b98f4e456ec37e1e59aebbc440a3f19630ee
|
4
|
+
data.tar.gz: f695548f4440427ef8730bef04f73a965af596dc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 92940a0b476087f8b4825d66f9ca6e925bf40054cc4935653a88717ca2dab721912f6d4683de987676b1d197c37bd0130a0a786ffdf92e9325618ff371878081
|
7
|
+
data.tar.gz: 0928cdafff8f26ae35ea25031f26350ecaabbad447be192156157fce1c03104a4fbfa42b120a8a6e187236be9aaacf939e5e3a4a0869f1673a9651ede5a03424
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Marshall Mickelson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Rack::Kibo
|
2
|
+
|
3
|
+
A Rack Middleware to present structured JSON responses
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'rack-kibo'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install rack-kibo
|
20
|
+
|
21
|
+
## What Kibo Does
|
22
|
+
|
23
|
+
Kibo will wrap any request for,or response containing the JSON
|
24
|
+
Content-Type `application/json` in a simple structured JSON object:
|
25
|
+
|
26
|
+
```javascript
|
27
|
+
{
|
28
|
+
"success": true,
|
29
|
+
"responded_at": 'utc date of response',
|
30
|
+
"version": 1,
|
31
|
+
"location": "/location/of/resource/requested",
|
32
|
+
"body": {
|
33
|
+
// your server's response object
|
34
|
+
}
|
35
|
+
}
|
36
|
+
```
|
37
|
+
|
38
|
+
Kibo will always return a successful HTTP Status code (anything less
|
39
|
+
than 400) unless there was an error within Kibo itself. If the response
|
40
|
+
from your server is an error code, Kibo returns HTTP 200, with the
|
41
|
+
`success` property of `false`
|
42
|
+
|
43
|
+
|
44
|
+
## Getting Started
|
45
|
+
|
46
|
+
### Rackup-based apps
|
47
|
+
|
48
|
+
Add the middleware to your Rack app
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
use Rack::Kibo
|
52
|
+
```
|
53
|
+
|
54
|
+
### Options
|
55
|
+
|
56
|
+
You can control how Kibo returns errors by supplying an `:expose_errors`
|
57
|
+
item in the initialization of your middleware
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
use Rack::Kibo, :expose_errors => true
|
61
|
+
```
|
62
|
+
|
63
|
+
`:expose_errors` defaults to `false`
|
64
|
+
|
65
|
+
Setting this value to `true` will return exception messages back to the
|
66
|
+
browser, potentially exposing your API's implementation. In addition to
|
67
|
+
exposing the error message, the original server response will be
|
68
|
+
returned.
|
69
|
+
|
70
|
+
### API Version Computation
|
71
|
+
|
72
|
+
Kibo looks for request path segments that contain `api/{version}` where
|
73
|
+
`version` is a number, or a number preceeded by either a lowercase `v`
|
74
|
+
or uppercase 'V'
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
"/some/api/1/order/get"
|
78
|
+
=> 1
|
79
|
+
|
80
|
+
"/some/api/v2/order/get"
|
81
|
+
=> 2
|
82
|
+
|
83
|
+
"/api/V3/order/get"
|
84
|
+
=> 3
|
85
|
+
```
|
86
|
+
|
87
|
+
Kibo works for any request path, but will return a version of `0` if it
|
88
|
+
does not find version information from the request path
|
89
|
+
|
90
|
+
## Development
|
91
|
+
|
92
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
93
|
+
|
94
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
95
|
+
|
96
|
+
## TODO
|
97
|
+
|
98
|
+
- [ ] Optionally allow servers response code to be returned by Kibo
|
99
|
+
instead of returning 200 for errors
|
100
|
+
- [ ] Optionally allow additional `Content-Type`'s to trigger Kibo
|
101
|
+
response wrapping (ex: `application/vnd+customJSON`)
|
102
|
+
|
103
|
+
## Contributing
|
104
|
+
|
105
|
+
Bug reports and pull requests are welcome on GitHub at
|
106
|
+
https://github.com/marshallmick007/rack-kibo.
|
107
|
+
|
108
|
+
|
109
|
+
## License
|
110
|
+
|
111
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
112
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rack/kibo"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/rack/kibo.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class SomethingTest
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
module Rack
|
9
|
+
##
|
10
|
+
# Rack Middleware which presents a clean API to JSON responses
|
11
|
+
class Kibo
|
12
|
+
##
|
13
|
+
# Regex to locate an API version in the path. Able to find the following
|
14
|
+
# - /path/api/1/something => 1
|
15
|
+
# - /path/api/V2/something => 2
|
16
|
+
# - /api/v13/omething => 13
|
17
|
+
# - /something/else/134/ => 0
|
18
|
+
API_PARSE_REGEX = /.*\/api\/[vV]?(\d*)\/?/
|
19
|
+
##
|
20
|
+
# Standard JSON content-type
|
21
|
+
JSON_CONTENT_TYPE = "application/json"
|
22
|
+
|
23
|
+
##
|
24
|
+
# Creates a new instance of the CleanApi middleware
|
25
|
+
# +app+: The rack app
|
26
|
+
# +options+: Hash of options to pass to the middleware
|
27
|
+
def initialize(app, options={})
|
28
|
+
@app = app
|
29
|
+
@options = options
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Rack Middleware entry-point
|
34
|
+
def call(env)
|
35
|
+
result = @app.call(env)
|
36
|
+
wrap_response env, result
|
37
|
+
rescue StandardError => e
|
38
|
+
wrap_response env, create_error_response(e, env, result)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
##
|
44
|
+
# Fetches the 'HTTP_ACCEPT' option from +env+
|
45
|
+
def request_accept(env)
|
46
|
+
env["HTTP_ACCEPT"]
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Fetches the 'PATH_INFO' rack variable from +env+
|
51
|
+
# Optionally will find and prioritize the 'REQUEST_PATH'
|
52
|
+
# if available
|
53
|
+
def request_path(env)
|
54
|
+
env["REQUEST_PATH"] || env["PATH_INFO"]
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Takes the output from the rack app and optionally
|
59
|
+
# wraps the +response+ with a simple JSON API structure
|
60
|
+
def wrap_response(env, response)
|
61
|
+
return response unless should_wrap_response?(env, response)
|
62
|
+
rs = {
|
63
|
+
:success => is_successful_http_status_code?(response[0]),
|
64
|
+
:responded_at => Time.now.utc,
|
65
|
+
:version => parse_api_version(env),
|
66
|
+
:location => request_path(env),
|
67
|
+
:body => create_payload(response[2])
|
68
|
+
}
|
69
|
+
response[2] = [ rs.to_json ]
|
70
|
+
response[1]["Content-Length"] = response[2][0].length.to_s
|
71
|
+
|
72
|
+
# TODO: support an option to allow user to emit original status codes
|
73
|
+
|
74
|
+
response[0] = 200 unless rs[:success]
|
75
|
+
response
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Convert exceptions into a proper response
|
80
|
+
def create_error_response(error, env, result)
|
81
|
+
rsp_env = {}
|
82
|
+
response = 'Error'
|
83
|
+
if should_wrap_response?(env, result)
|
84
|
+
server_result = nil
|
85
|
+
if result
|
86
|
+
env = result[1]
|
87
|
+
server_result = result[2]
|
88
|
+
end
|
89
|
+
response = create_error_json(error, server_result)
|
90
|
+
end
|
91
|
+
error_result = [500, rsp_env, [response]]
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Generates the 'payload' element of the API response
|
96
|
+
def create_payload(response_data)
|
97
|
+
payload = []
|
98
|
+
response_data.each do |data|
|
99
|
+
payload << JSON.parse(data)
|
100
|
+
end
|
101
|
+
|
102
|
+
nil if payload.length == 0
|
103
|
+
payload if payload.length > 1
|
104
|
+
payload[0] if payload.length == 1
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Parses the API version from the request path
|
109
|
+
def parse_api_version(env)
|
110
|
+
matches = API_PARSE_REGEX.match(request_path(env))
|
111
|
+
return 0 unless matches
|
112
|
+
matches.captures[0].to_i
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Generates an error response payload
|
117
|
+
def create_error_json(error, data)
|
118
|
+
result = {
|
119
|
+
:error => {
|
120
|
+
:message => 'Error'
|
121
|
+
}
|
122
|
+
}
|
123
|
+
if @options[:expose_errors]
|
124
|
+
result[:error][:message] = error.message
|
125
|
+
result[:error][:data] = data
|
126
|
+
end
|
127
|
+
result.to_json
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# Determines if the HTTP Status code is considered
|
132
|
+
# a successful response
|
133
|
+
def is_successful_http_status_code?(code)
|
134
|
+
code < 400
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Determines if the response should be wrapped in
|
139
|
+
# the CleanApi object
|
140
|
+
def should_wrap_response?(env, response)
|
141
|
+
client_request = is_supported_content_type? request_accept(env)
|
142
|
+
server_response = response_should_be_json? response
|
143
|
+
server_response || client_request
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Determines if the response Content-Type is supposed
|
148
|
+
# to be wrapped in the CleanApi object
|
149
|
+
def response_should_be_json?(response)
|
150
|
+
return false unless response
|
151
|
+
is_supported_content_type? response[1]["Content-Type"]
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Determines if the +content_type+ dictates that the
|
156
|
+
# response should be wrapped in the CleanApi
|
157
|
+
def is_supported_content_type?(content_type)
|
158
|
+
# TODO: Should we allow user-defined accept-encodings?
|
159
|
+
content_type == JSON_CONTENT_TYPE
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
data/rack-kibo.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rack/kibo/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rack-kibo"
|
8
|
+
spec.version = Rack::Kibo::VERSION
|
9
|
+
spec.authors = ["Marshall Mickelson"]
|
10
|
+
spec.email = ["rubygems@0x07.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A Rack Middleware to present structured JSON responses}
|
13
|
+
spec.homepage = "https://github.com/marshallmick007/rack-kibo"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
18
|
+
#if spec.respond_to?(:metadata)
|
19
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
20
|
+
#else
|
21
|
+
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
22
|
+
#end
|
23
|
+
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_dependency "rack"
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-kibo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marshall Mickelson
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- rubygems@0x07.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/console
|
84
|
+
- bin/setup
|
85
|
+
- lib/rack/kibo.rb
|
86
|
+
- lib/rack/kibo/kibo.rb
|
87
|
+
- lib/rack/kibo/version.rb
|
88
|
+
- rack-kibo.gemspec
|
89
|
+
homepage: https://github.com/marshallmick007/rack-kibo
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.5.1
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: A Rack Middleware to present structured JSON responses
|
113
|
+
test_files: []
|