blanket_wrapper 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 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