blanket_wrapper 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4028f6fe83d360d8cdc4bc7af5d2c25b1c9b30f1
4
- data.tar.gz: f94aded281f1b23a9e2f4a311dcee1ae071a23f7
3
+ metadata.gz: 80891d01cd391a6ca57b8cd1d2d266a479529a25
4
+ data.tar.gz: 8276eaabece824b10f87d5c05bfa043218ca4538
5
5
  SHA512:
6
- metadata.gz: 2e2b774f5d56de52201ff07bcae76b2b85ccd1c9cbda67d7c2f7cb8de488e6e69acd35dcf45adc40f1540e1538782ac0454995c162ecddd90a1eb4fe49555efa
7
- data.tar.gz: 56f747dd7b792f21ecc8df6bc028d802e85a3b00bc9d43d04e40c4da448b7f7fe5cf06ab1aa4adc98141c5aeaae1db1f1cdca814fb9f060539ad0f0a7dfc26a5
6
+ metadata.gz: 1206873393b17fc7f110f04d019cc083f0a7b6bd6ef6c2fa2a8ac2741f093b3458d61e5267b5236cefd12f423f7ba2a8b4191ddd0756fc5751f1b5b220652b01
7
+ data.tar.gz: c6591d74a75cc068784d9fa9e9327f8d6ebcea80265bb8c6ebf30f6e69268dd093dbfcb8d92172b015010bee2a2ed81a182f11b592bcda40292ce84300834b2b
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
  [![Build Status](https://travis-ci.org/inf0rmer/blanket.svg?branch=master)](https://travis-ci.org/inf0rmer/blanket)
3
3
  [![Coverage Status](https://img.shields.io/coveralls/inf0rmer/blanket.svg)](https://coveralls.io/r/inf0rmer/blanket?branch=master)
4
4
  [![Code Climate](https://codeclimate.com/github/inf0rmer/blanket/badges/gpa.svg)](https://codeclimate.com/github/inf0rmer/blanket)
5
+ [![Inline docs](http://inch-ci.org/github/inf0rmer/blanket.svg?branch=master)](http://inch-ci.org/github/inf0rmer/blanket)
5
6
 
6
7
 
7
8
  A dead simple API wrapper.
@@ -11,7 +12,7 @@ A dead simple API wrapper.
11
12
  Add this line to your application's Gemfile:
12
13
 
13
14
  ```ruby
14
- gem 'blanket'
15
+ gem 'blanket_wrapper'
15
16
  ```
16
17
 
17
18
  And then execute:
@@ -20,7 +21,7 @@ And then execute:
20
21
 
21
22
  Or install it yourself as:
22
23
 
23
- $ gem install blanket
24
+ $ gem install blanket_wrapper
24
25
 
25
26
  ## Usage
26
27
 
@@ -134,6 +135,26 @@ users_endpoint = api.users(55)
134
135
  users_endpoint.extension = :xml
135
136
  ```
136
137
 
138
+ ### Handling Exceptions
139
+
140
+ Blanket will raise exceptions for HTTP errors encountered while making requests. Exception subclasses are raised for well known errors (404, 500, etc.) but for other status codes a default `Blanket::Exception` will be raised instead.
141
+
142
+ ```ruby
143
+ begin
144
+ api.thingamajig.get
145
+ rescue Blanket::ResourceNotFound => e
146
+ e.code
147
+ # => 404
148
+
149
+ e.message
150
+ # => "404: Resource Not Found"
151
+
152
+ # The HTTP body, ie. the error message sent by the server
153
+ e.body
154
+ # => "Could not find this resource!"
155
+ end
156
+ ```
157
+
137
158
  ## Contributing
138
159
 
139
160
  1. Fork it ( https://github.com/[my-github-username]/blanket/fork )
data/lib/blanket.rb CHANGED
@@ -1,8 +1,10 @@
1
- require "blanket/version"
2
- require "blanket/response"
3
- require "blanket/wrapper"
1
+ require_relative "blanket/version"
2
+ require_relative "blanket/response"
3
+ require_relative "blanket/exception"
4
+ require_relative "blanket/wrapper"
4
5
  require 'httparty'
5
6
 
7
+ # The main Blanket module
6
8
  module Blanket
7
9
  # Wraps an API using Blanket::Wrapper
8
10
  def self.wrap(*args)
@@ -0,0 +1,124 @@
1
+ module Blanket
2
+
3
+ # A Map of HTTP status codes and their names
4
+ STATUSES = {100 => 'Continue',
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
+
26
+ 400 => 'Bad Request',
27
+ 401 => 'Unauthorized',
28
+ 402 => 'Payment Required',
29
+ 403 => 'Forbidden',
30
+ 404 => 'Resource Not Found',
31
+ 405 => 'Method Not Allowed',
32
+ 406 => 'Not Acceptable',
33
+ 407 => 'Proxy Authentication Required',
34
+ 408 => 'Request Timeout',
35
+ 409 => 'Conflict',
36
+ 410 => 'Gone',
37
+ 411 => 'Length Required',
38
+ 412 => 'Precondition Failed',
39
+ 413 => 'Request Entity Too Large',
40
+ 414 => 'Request-URI Too Long',
41
+ 415 => 'Unsupported Media Type',
42
+ 416 => 'Requested Range Not Satisfiable',
43
+ 417 => 'Expectation Failed',
44
+ 418 => 'I\'m A Teapot', #RFC2324
45
+ 421 => 'Too Many Connections From This IP',
46
+ 422 => 'Unprocessable Entity', #WebDAV
47
+ 423 => 'Locked', #WebDAV
48
+ 424 => 'Failed Dependency', #WebDAV
49
+ 425 => 'Unordered Collection', #WebDAV
50
+ 426 => 'Upgrade Required',
51
+ 428 => 'Precondition Required', #RFC6585
52
+ 429 => 'Too Many Requests', #RFC6585
53
+ 431 => 'Request Header Fields Too Large', #RFC6585
54
+ 449 => 'Retry With', #Microsoft
55
+ 450 => 'Blocked By Windows Parental Controls', #Microsoft
56
+
57
+ 500 => 'Internal Server Error',
58
+ 501 => 'Not Implemented',
59
+ 502 => 'Bad Gateway',
60
+ 503 => 'Service Unavailable',
61
+ 504 => 'Gateway Timeout',
62
+ 505 => 'HTTP Version Not Supported',
63
+ 506 => 'Variant Also Negotiates',
64
+ 507 => 'Insufficient Storage', #WebDAV
65
+ 509 => 'Bandwidth Limit Exceeded', #Apache
66
+ 510 => 'Not Extended',
67
+ 511 => 'Network Authentication Required', # RFC6585
68
+ }
69
+
70
+ # The base class for all Blanket Exceptions
71
+ class Exception < RuntimeError
72
+ # Attribute writer for the Exception message
73
+ attr_writer :message
74
+ # Attribute reader for the Exception http response
75
+ attr_reader :response
76
+
77
+ # Creates a new exception
78
+ # @param [HTTParty::Response] response the HTTP Response
79
+ # @return [Blanket::Exception] The Blanket Exception object
80
+ def initialize(response = nil)
81
+ @response = response
82
+ end
83
+
84
+ # Returns the HTTP response body
85
+ def body
86
+ @response.body.to_s if @response
87
+ end
88
+
89
+ # Returns the HTTP status code
90
+ def code
91
+ @response.code.to_i if @response
92
+ end
93
+
94
+ # Returns a formatted error message
95
+ def message
96
+ @message || self.class.name
97
+ end
98
+
99
+ # Returns a stringified error message
100
+ def inspect
101
+ "#{message}: #{body}"
102
+ end
103
+
104
+ # Returns a stringified error message
105
+ def to_s
106
+ inspect
107
+ end
108
+ end
109
+
110
+ # We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
111
+ module Exceptions
112
+ # Map http status codes to the corresponding exception class
113
+ EXCEPTIONS_MAP = {}
114
+ end
115
+
116
+ STATUSES.each_pair do |code, message|
117
+ klass = Class.new(Exception) do
118
+ send(:define_method, :message) {"#{code ? "#{code} " : ''}#{message}"}
119
+ end
120
+
121
+ klass_constant = const_set message.delete(' \-\''), klass
122
+ Exceptions::EXCEPTIONS_MAP[code] = klass_constant
123
+ end
124
+ end
@@ -2,6 +2,8 @@ require 'recursive-open-struct'
2
2
  require 'json'
3
3
 
4
4
  module Blanket
5
+
6
+ # The Response class wraps HTTP responses
5
7
  class Response
6
8
  # Attribute reader for the original JSON payload string
7
9
  attr_reader :payload
@@ -1,4 +1,4 @@
1
1
  module Blanket
2
2
  # Current gem version
3
- VERSION = "1.0.1"
3
+ VERSION = "1.1.0"
4
4
  end
@@ -1,4 +1,5 @@
1
1
  module Blanket
2
+ # The Wrapper class wraps an API
2
3
  class Wrapper
3
4
  class << self
4
5
  private
@@ -67,9 +68,12 @@ module Blanket
67
68
  headers: headers
68
69
  }.reject { |k, v| v.nil? || v.empty? })
69
70
 
70
- body = (response.respond_to? :body) ? response.body : nil
71
-
72
- (body.is_a? Array) ? body.map(Response.new) : Response.new(body)
71
+ if response.code <= 400
72
+ body = (response.respond_to? :body) ? response.body : nil
73
+ (body.is_a? Array) ? body.map(Response.new) : Response.new(body)
74
+ else
75
+ raise Blanket::Exceptions::EXCEPTIONS_MAP[response.code].new(response)
76
+ end
73
77
  end
74
78
 
75
79
  def merged_headers(headers)
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'blanket/exception'
3
+
4
+ describe Blanket::Exception do
5
+ describe "#message" do
6
+ context "When a message is not set" do
7
+ let :e do
8
+ Blanket::Exception.new
9
+ end
10
+
11
+ it "returns its Class name" do
12
+ expect(e.message).to eq("Blanket::Exception")
13
+ end
14
+ end
15
+
16
+ context "When a message is set" do
17
+ let :message do
18
+ "A custom exception message"
19
+ end
20
+
21
+ let :e do
22
+ e = Blanket::Exception.new
23
+ e.message = message
24
+ e
25
+ end
26
+
27
+ it "returns the custom message" do
28
+ expect(e.message).to eq(message)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#response" do
34
+ let :response do
35
+ double("HTTP Response", code: 500)
36
+ end
37
+
38
+ let :e do
39
+ Blanket::InternalServerError.new(response)
40
+ end
41
+
42
+ it "allows access to the HTTP status code" do
43
+ expect(e.response).to eq(response)
44
+ end
45
+ end
46
+
47
+ describe "#code" do
48
+ let :response do
49
+ double("HTTP Response", code: 500)
50
+ end
51
+
52
+ let :e do
53
+ Blanket::InternalServerError.new(response)
54
+ end
55
+
56
+ it "allows access to the HTTP status code" do
57
+ expect(e.code).to eq(response.code)
58
+ end
59
+ end
60
+
61
+ describe "#body" do
62
+ let :body do
63
+ "Internal Server Error"
64
+ end
65
+
66
+ let :response do
67
+ double("HTTP Response", code: 500, body: body)
68
+ end
69
+
70
+ let :e do
71
+ Blanket::InternalServerError.new(response)
72
+ end
73
+
74
+ it "allows access to the HTTP response body" do
75
+ expect(e.body).to eq(body)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe Blanket::ResourceNotFound do
81
+ let :e do
82
+ e = Blanket::ResourceNotFound.new
83
+ end
84
+
85
+ it "inherits from Blanket::Exception" do
86
+ expect(e).to be_kind_of(Blanket::Exception)
87
+ end
88
+
89
+ it "has a '404 Resource Not Found' message" do
90
+ expect(e.message).to eq("404 Resource Not Found")
91
+ end
92
+ end
93
+
94
+ describe Blanket::InternalServerError do
95
+ let :e do
96
+ e = Blanket::InternalServerError.new
97
+ end
98
+
99
+ it "inherits from Blanket::Exception" do
100
+ expect(e).to be_kind_of(Blanket::Exception)
101
+ end
102
+
103
+ it "has a '500 Internal Server Error' message" do
104
+ expect(e.message).to eq("500 Internal Server Error")
105
+ end
106
+ end
@@ -7,11 +7,9 @@ describe "Blanket::Wrapper" do
7
7
  end
8
8
 
9
9
  describe 'Making Requests' do
10
- before :each do
11
- allow(HTTParty).to receive(:get)
12
- end
13
-
14
10
  it 'resets after performing a request' do
11
+ allow(HTTParty).to receive(:get) { StubbedResponse.new }
12
+
15
13
  api.users.get()
16
14
  api.videos.get()
17
15
 
@@ -20,11 +18,12 @@ describe "Blanket::Wrapper" do
20
18
 
21
19
  describe "Response" do
22
20
  before :each do
23
- stub_request(:get, "http://api.example.org/users").to_return(:body => '{"title": "Something"}')
21
+ stub_request(:get, "http://api.example.org/users")
22
+ .to_return(:body => '{"title": "Something"}')
24
23
  end
25
24
 
26
25
  let :response do
27
- api.users.get()
26
+ api.users.get
28
27
  end
29
28
 
30
29
  it "returns a Blanket::Response instance" do
@@ -32,7 +31,27 @@ describe "Blanket::Wrapper" do
32
31
  end
33
32
  end
34
33
 
34
+ describe "Exceptions" do
35
+ let :api do
36
+ Blanket::wrap("http://api.example.org")
37
+ end
38
+
39
+ describe "500" do
40
+ before :each do
41
+ stub_request(:get, "http://api.example.org/users").to_return(:status => 500, :body => "You've been met with a terrible fate, haven't you?")
42
+ end
43
+
44
+ it "raises a Blanket::InternalServerError exception" do
45
+ expect { api.users.get }.to raise_exception(Blanket::InternalServerError)
46
+ end
47
+ end
48
+ end
49
+
35
50
  describe 'Resource identification' do
51
+ before do
52
+ allow(HTTParty).to receive(:get) { StubbedResponse.new }
53
+ end
54
+
36
55
  context 'When using a resource method' do
37
56
  it 'allows identifying a resource' do
38
57
  api.users(55).get()
@@ -57,6 +76,10 @@ describe "Blanket::Wrapper" do
57
76
  end
58
77
 
59
78
  describe 'Headers' do
79
+ before :each do
80
+ allow(HTTParty).to receive(:get) { StubbedResponse.new }
81
+ end
82
+
60
83
  it 'allows sending headers in a request' do
61
84
  api.users(55).get(headers: {foo: 'bar'})
62
85
 
@@ -72,6 +95,10 @@ describe "Blanket::Wrapper" do
72
95
  end
73
96
 
74
97
  describe 'Parameters' do
98
+ before :each do
99
+ allow(HTTParty).to receive(:get) { StubbedResponse.new }
100
+ end
101
+
75
102
  it 'allows sending parameters in a request' do
76
103
  api.users(55).get(params: {foo: 'bar'})
77
104
 
@@ -80,7 +107,11 @@ describe "Blanket::Wrapper" do
80
107
  end
81
108
 
82
109
  describe 'URL Extension' do
83
- it 'allows setting an extension for a request', :wip => true do
110
+ before :each do
111
+ allow(HTTParty).to receive(:get) { StubbedResponse.new }
112
+ end
113
+
114
+ it 'allows setting an extension for a request' do
84
115
  users_endpoint = api.users(55)
85
116
  users_endpoint.extension = :json
86
117
  users_endpoint.get
@@ -98,8 +129,8 @@ describe "Blanket::Wrapper" do
98
129
  end
99
130
 
100
131
  describe '#get' do
101
- before :each do
102
- allow(HTTParty).to receive(:get)
132
+ before do
133
+ allow(HTTParty).to receive(:get) { StubbedResponse.new }
103
134
  end
104
135
 
105
136
  it 'GETs a resource' do
@@ -110,8 +141,8 @@ describe "Blanket::Wrapper" do
110
141
  end
111
142
 
112
143
  describe '#post' do
113
- before :each do
114
- allow(HTTParty).to receive(:post)
144
+ before do
145
+ allow(HTTParty).to receive(:post) { StubbedResponse.new }
115
146
  end
116
147
 
117
148
  it 'POSTs a resource' do
@@ -122,8 +153,8 @@ describe "Blanket::Wrapper" do
122
153
  end
123
154
 
124
155
  describe '#put' do
125
- before :each do
126
- allow(HTTParty).to receive(:put)
156
+ before do
157
+ allow(HTTParty).to receive(:put) { StubbedResponse.new }
127
158
  end
128
159
 
129
160
  it 'PUTs a resource' do
@@ -134,8 +165,8 @@ describe "Blanket::Wrapper" do
134
165
  end
135
166
 
136
167
  describe '#patch' do
137
- before :each do
138
- allow(HTTParty).to receive(:patch)
168
+ before do
169
+ allow(HTTParty).to receive(:patch) { StubbedResponse.new }
139
170
  end
140
171
 
141
172
  it 'PATCHes a resource' do
@@ -146,8 +177,8 @@ describe "Blanket::Wrapper" do
146
177
  end
147
178
 
148
179
  describe '#delete' do
149
- before :each do
150
- allow(HTTParty).to receive(:delete)
180
+ before do
181
+ allow(HTTParty).to receive(:delete) { StubbedResponse.new }
151
182
  end
152
183
 
153
184
  it 'DELETEs a resource' do
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,12 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'coveralls'
5
5
  Coveralls.wear!
6
6
 
7
+ class StubbedResponse
8
+ def code
9
+ 200
10
+ end
11
+ end
12
+
7
13
  require 'pry'
8
14
  require 'webmock/rspec'
9
15
  require 'blanket'
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.0.1
4
+ version: 1.1.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: 2014-12-21 00:00:00.000000000 Z
11
+ date: 2014-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -225,9 +225,11 @@ files:
225
225
  - Rakefile
226
226
  - blanket.gemspec
227
227
  - lib/blanket.rb
228
+ - lib/blanket/exception.rb
228
229
  - lib/blanket/response.rb
229
230
  - lib/blanket/version.rb
230
231
  - lib/blanket/wrapper.rb
232
+ - spec/blanket/exception_spec.rb
231
233
  - spec/blanket/response_spec.rb
232
234
  - spec/blanket/wrapper_spec.rb
233
235
  - spec/blanket_spec.rb
@@ -257,6 +259,7 @@ signing_key:
257
259
  specification_version: 4
258
260
  summary: A dead simple API wrapper. Access your data with style.
259
261
  test_files:
262
+ - spec/blanket/exception_spec.rb
260
263
  - spec/blanket/response_spec.rb
261
264
  - spec/blanket/wrapper_spec.rb
262
265
  - spec/blanket_spec.rb