blanket_wrapper 1.1.0 → 1.2.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/README.md +30 -1
- data/lib/blanket/exception.rb +10 -28
- data/lib/blanket/response.rb +6 -9
- data/lib/blanket/version.rb +1 -1
- data/lib/blanket/wrapper.rb +23 -15
- data/spec/blanket/wrapper_spec.rb +30 -0
- metadata +2 -3
- data/LICENSE.txt +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4919971f12da2062b5d5cd9b0152d820acce367
|
4
|
+
data.tar.gz: d5ffa6e823b1a2a00647d13b23a85c78a71b52ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e489971f0588e4d32bc874e22fbe088f13d34cddacd67966e4fb71deb60d234285d8b48c8200114dcb28bdf36cb93654b54bfbf4dc4e0ee8690bd8f5563586d
|
7
|
+
data.tar.gz: 23a7795896868c49f0df75162fc0093f34e9ab63f2f83eb8a09624df8da7c30326cd722fd699922c07db432922ca586da8d79f5e625390b9400c11cb7fd359fc
|
data/README.md
CHANGED
@@ -7,6 +7,19 @@
|
|
7
7
|
|
8
8
|
A dead simple API wrapper.
|
9
9
|
|
10
|
+
**Table of Contents**
|
11
|
+
|
12
|
+
- [Installation](#installation)
|
13
|
+
- [Usage](#usage)
|
14
|
+
- [Quick demo](#quick-demo)
|
15
|
+
- [How it works](#how-it-works)
|
16
|
+
- [Responses](#responses)
|
17
|
+
- [Request Parameters](#request-parameters)
|
18
|
+
- [Headers](#headers)
|
19
|
+
- [Extensions](#extensions)
|
20
|
+
- [Handling Exceptions](#handling-exceptions)
|
21
|
+
- [Contributing](#contributing)
|
22
|
+
|
10
23
|
## Installation
|
11
24
|
|
12
25
|
Add this line to your application's Gemfile:
|
@@ -28,6 +41,8 @@ Or install it yourself as:
|
|
28
41
|
### Quick demo
|
29
42
|
|
30
43
|
```ruby
|
44
|
+
require 'blanket'
|
45
|
+
|
31
46
|
github = Blanket.wrap("https://api.github.com")
|
32
47
|
|
33
48
|
# Get some user's info
|
@@ -104,6 +119,14 @@ repos.map(&:name)
|
|
104
119
|
# => ["analytics-ios", "aztec", "fusebox", ...]
|
105
120
|
```
|
106
121
|
|
122
|
+
### Request Body
|
123
|
+
You can make requests with body using the `body` option:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
api = Blanket::wrap("http://api.example.org")
|
127
|
+
api.messages.post(body: 'Hello')
|
128
|
+
```
|
129
|
+
|
107
130
|
### Request Parameters
|
108
131
|
Blanket supports appending parameters to your requests:
|
109
132
|
|
@@ -112,6 +135,12 @@ api.users(55).get(params: {foo: 'bar'})
|
|
112
135
|
# => "http://api.example.org/users/55?foo=bar"
|
113
136
|
```
|
114
137
|
|
138
|
+
You can also set default params for all your requests on initialization:
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
api = Blanket::wrap("http://api.example.org", params: {access_token: 'my secret token'})
|
142
|
+
```
|
143
|
+
|
115
144
|
### Headers
|
116
145
|
HTTP Headers are always useful when accessing an API, so Blanket makes it easy for you to specify them, either globally or on a per-request basis:
|
117
146
|
|
@@ -157,7 +186,7 @@ end
|
|
157
186
|
|
158
187
|
## Contributing
|
159
188
|
|
160
|
-
1. Fork it ( https://github.com/
|
189
|
+
1. Fork it ( https://github.com/inf0rmer/blanket/fork )
|
161
190
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
162
191
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
163
192
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/lib/blanket/exception.rb
CHANGED
@@ -1,28 +1,7 @@
|
|
1
1
|
module Blanket
|
2
2
|
|
3
|
-
# A Map of HTTP status codes and their names
|
4
|
-
STATUSES = {
|
5
|
-
101 => 'Switching Protocols',
|
6
|
-
102 => 'Processing', #WebDAV
|
7
|
-
|
8
|
-
200 => 'OK',
|
9
|
-
201 => 'Created',
|
10
|
-
202 => 'Accepted',
|
11
|
-
203 => 'Non-Authoritative Information', # http/1.1
|
12
|
-
204 => 'No Content',
|
13
|
-
205 => 'Reset Content',
|
14
|
-
206 => 'Partial Content',
|
15
|
-
207 => 'Multi-Status', #WebDAV
|
16
|
-
|
17
|
-
300 => 'Multiple Choices',
|
18
|
-
301 => 'Moved Permanently',
|
19
|
-
302 => 'Found',
|
20
|
-
303 => 'See Other', # http/1.1
|
21
|
-
304 => 'Not Modified',
|
22
|
-
305 => 'Use Proxy', # http/1.1
|
23
|
-
306 => 'Switch Proxy', # no longer used
|
24
|
-
307 => 'Temporary Redirect', # http/1.1
|
25
|
-
|
3
|
+
# A Map of "error" HTTP status codes and their names
|
4
|
+
STATUSES = {
|
26
5
|
400 => 'Bad Request',
|
27
6
|
401 => 'Unauthorized',
|
28
7
|
402 => 'Payment Required',
|
@@ -101,21 +80,24 @@ module Blanket
|
|
101
80
|
"#{message}: #{body}"
|
102
81
|
end
|
103
82
|
|
104
|
-
|
105
|
-
def to_s
|
106
|
-
inspect
|
107
|
-
end
|
83
|
+
alias_method :to_s, :inspect
|
108
84
|
end
|
109
85
|
|
110
86
|
# We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
111
87
|
module Exceptions
|
112
88
|
# Map http status codes to the corresponding exception class
|
113
89
|
EXCEPTIONS_MAP = {}
|
90
|
+
|
91
|
+
def self.generate_from_response(response)
|
92
|
+
(EXCEPTIONS_MAP[response.code] || Exception).new(response)
|
93
|
+
end
|
114
94
|
end
|
115
95
|
|
116
96
|
STATUSES.each_pair do |code, message|
|
117
97
|
klass = Class.new(Exception) do
|
118
|
-
|
98
|
+
define_method :message do
|
99
|
+
"#{code} #{message}"
|
100
|
+
end
|
119
101
|
end
|
120
102
|
|
121
103
|
klass_constant = const_set message.delete(' \-\''), klass
|
data/lib/blanket/response.rb
CHANGED
@@ -21,22 +21,19 @@ module Blanket
|
|
21
21
|
# Allows accessing the payload's JSON keys through methods.
|
22
22
|
def method_missing(method, *args, &block)
|
23
23
|
if payload.respond_to? method
|
24
|
-
payload.
|
24
|
+
payload.public_send method, *args, &block
|
25
25
|
else
|
26
26
|
super
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
def payload_from_json(json)
|
31
|
-
|
32
|
-
|
33
|
-
RecursiveOpenStruct.new item, :recurse_over_arrays => true
|
34
|
-
end
|
35
|
-
|
36
|
-
(parsed.count == 1) ? parsed.first : parsed
|
37
|
-
else
|
38
|
-
nil
|
31
|
+
parsed = [json].flatten.map do |item|
|
32
|
+
RecursiveOpenStruct.new item, recurse_over_arrays: true
|
39
33
|
end
|
34
|
+
|
35
|
+
(parsed.count == 1) ? parsed.first : parsed
|
40
36
|
end
|
37
|
+
|
41
38
|
end
|
42
39
|
end
|
data/lib/blanket/version.rb
CHANGED
data/lib/blanket/wrapper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Blanket
|
2
|
-
# The Wrapper class wraps an API
|
3
2
|
class Wrapper
|
4
3
|
class << self
|
5
4
|
private
|
@@ -7,7 +6,7 @@ module Blanket
|
|
7
6
|
# @method $1()
|
8
7
|
# Performs a $1 request on the wrapped URL
|
9
8
|
# @param [String, Symbol, Numeric] id The resource identifier to attach to the last part of the request
|
10
|
-
# @param [Hash] options An options hash with values for :headers, :extension and :
|
9
|
+
# @param [Hash] options An options hash with values for :headers, :extension, :params and :body
|
11
10
|
# @return [Blanket::Response, Array] A wrapped Blanket::Response or an Array
|
12
11
|
def add_action(action)
|
13
12
|
define_method(action) do |id=nil, options={}|
|
@@ -20,6 +19,10 @@ module Blanket
|
|
20
19
|
# should be applied to all requests
|
21
20
|
attr_accessor :headers
|
22
21
|
|
22
|
+
# Attribute accessor for params that
|
23
|
+
# should be applied to all requests
|
24
|
+
attr_accessor :params
|
25
|
+
|
23
26
|
# Attribute accessor for file extension that
|
24
27
|
# should be appended to all requests
|
25
28
|
attr_accessor :extension
|
@@ -32,12 +35,13 @@ module Blanket
|
|
32
35
|
|
33
36
|
# Wraps the base URL for an API
|
34
37
|
# @param [String, Symbol] base_uri The root URL of the API you wish to wrap.
|
35
|
-
# @param [Hash] options An options hash with global values for :headers and :
|
38
|
+
# @param [Hash] options An options hash with global values for :headers, :extension and :params
|
36
39
|
# @return [Blanket] The Blanket object wrapping the API
|
37
40
|
def initialize(base_uri, options={})
|
38
41
|
@base_uri = base_uri
|
39
42
|
@uri_parts = []
|
40
|
-
@headers =
|
43
|
+
@headers = options[:headers] || {}
|
44
|
+
@params = options[:params] || {}
|
41
45
|
@extension = options[:extension]
|
42
46
|
end
|
43
47
|
|
@@ -46,7 +50,8 @@ module Blanket
|
|
46
50
|
def method_missing(method, *args, &block)
|
47
51
|
Wrapper.new uri_from_parts([method, args.first]), {
|
48
52
|
headers: @headers,
|
49
|
-
extension: @extension
|
53
|
+
extension: @extension,
|
54
|
+
params: @params
|
50
55
|
}
|
51
56
|
end
|
52
57
|
|
@@ -57,34 +62,37 @@ module Blanket
|
|
57
62
|
end
|
58
63
|
|
59
64
|
headers = merged_headers(options[:headers])
|
65
|
+
params = merged_params(options[:params])
|
60
66
|
uri = uri_from_parts([id])
|
61
67
|
|
62
68
|
if @extension
|
63
69
|
uri = "#{uri}.#{extension}"
|
64
70
|
end
|
65
71
|
|
66
|
-
response = HTTParty.
|
67
|
-
query:
|
68
|
-
headers: headers
|
69
|
-
|
72
|
+
response = HTTParty.public_send(method, uri, {
|
73
|
+
query: params,
|
74
|
+
headers: headers,
|
75
|
+
body: options[:body]
|
76
|
+
}.reject { |_, value| value.nil? || value.empty? })
|
70
77
|
|
71
78
|
if response.code <= 400
|
72
79
|
body = (response.respond_to? :body) ? response.body : nil
|
73
80
|
(body.is_a? Array) ? body.map(Response.new) : Response.new(body)
|
74
81
|
else
|
75
|
-
raise Blanket::Exceptions
|
82
|
+
raise Blanket::Exceptions.generate_from_response(response)
|
76
83
|
end
|
77
84
|
end
|
78
85
|
|
79
86
|
def merged_headers(headers)
|
80
|
-
|
87
|
+
@headers.merge(headers || {})
|
88
|
+
end
|
89
|
+
|
90
|
+
def merged_params(params)
|
91
|
+
@params.merge(params || {})
|
81
92
|
end
|
82
93
|
|
83
94
|
def uri_from_parts(parts)
|
84
|
-
parts
|
85
|
-
.clone
|
86
|
-
.compact
|
87
|
-
.inject(@base_uri.clone) { |memo, part| memo << "/#{part}" }
|
95
|
+
([@base_uri] + parts).compact.join('/')
|
88
96
|
end
|
89
97
|
end
|
90
98
|
end
|
@@ -45,6 +45,16 @@ describe "Blanket::Wrapper" do
|
|
45
45
|
expect { api.users.get }.to raise_exception(Blanket::InternalServerError)
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
describe "522, a non registered invalid status code" do
|
50
|
+
before :each do
|
51
|
+
stub_request(:get, "http://api.example.org/users").to_return(status: 522, body: "You've been met with a terrible fate, haven't you?")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "raises a generic instance of Blanket::Exception" do
|
55
|
+
expect { api.users.get }.to raise_exception(Blanket::Exception)
|
56
|
+
end
|
57
|
+
end
|
48
58
|
end
|
49
59
|
|
50
60
|
describe 'Resource identification' do
|
@@ -104,6 +114,13 @@ describe "Blanket::Wrapper" do
|
|
104
114
|
|
105
115
|
expect(HTTParty).to have_received(:get).with('http://api.example.org/users/55', query: {foo: 'bar'})
|
106
116
|
end
|
117
|
+
|
118
|
+
it 'allows setting parameters globally' do
|
119
|
+
api = Blanket::wrap("http://api.example.org", params: {token: 'my secret token'})
|
120
|
+
api.users(55).get(params: {foo: 'bar'})
|
121
|
+
|
122
|
+
expect(HTTParty).to have_received(:get).with('http://api.example.org/users/55', query: {token: 'my secret token', foo: 'bar'})
|
123
|
+
end
|
107
124
|
end
|
108
125
|
|
109
126
|
describe 'URL Extension' do
|
@@ -126,6 +143,19 @@ describe "Blanket::Wrapper" do
|
|
126
143
|
expect(HTTParty).to have_received(:get).with('http://api.example.org/users/55.xml', anything())
|
127
144
|
end
|
128
145
|
end
|
146
|
+
|
147
|
+
describe 'Body' do
|
148
|
+
before :each do
|
149
|
+
allow(HTTParty).to receive(:post) { StubbedResponse.new }
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'allows setting the body for a request' do
|
153
|
+
api = Blanket::wrap("http://api.example.org")
|
154
|
+
api.users(55).post(body: { this_key: :this_value }.to_json)
|
155
|
+
|
156
|
+
expect(HTTParty).to have_received(:post).with('http://api.example.org/users/55', body: { this_key: :this_value }.to_json)
|
157
|
+
end
|
158
|
+
end
|
129
159
|
end
|
130
160
|
|
131
161
|
describe '#get' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blanket_wrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno Abrantes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -220,7 +220,6 @@ files:
|
|
220
220
|
- Gemfile
|
221
221
|
- Guardfile
|
222
222
|
- LICENSE
|
223
|
-
- LICENSE.txt
|
224
223
|
- README.md
|
225
224
|
- Rakefile
|
226
225
|
- blanket.gemspec
|
data/LICENSE.txt
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
Copyright (c) 2014 Bruno Abrantes
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|