reverb-service-client 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 18035f451800fb0b77df7989ef400e556e8b6d6d
4
+ data.tar.gz: 18b4d640f5e72c5b25138ae39a1e8f8d461d044d
5
+ SHA512:
6
+ metadata.gz: c81dc9da01df6b6dd8213fad775c0f862547679f872120f90c6ba14b1d25742dc70ee188e8f25f3a25eca9a26d86b00111431155b04c30968a5eb97d92cdb070
7
+ data.tar.gz: 801ed6f8b4c0fad2c69cf13a2a759cc7510525a981124ea223a48381b8188541410d5da875f27dbdbd004d43bf11a138547937196168eea28bb8cd890d411915
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in service-client.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec'
8
+ gem 'webmock'
9
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Yan Pritzker
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.
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Reverb::Service::Client
2
+
3
+ A base class for clients of Reverb services. Provides basic abstraction over http.
4
+
5
+
6
+ ## Usage
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'reverb-service-client'
11
+
12
+ Require it
13
+
14
+ require 'reverb/service/client'
15
+
16
+ Inherit from Reverb::Service::Client in your client:
17
+
18
+ class MyClient < Reverb::Service::Client
19
+ end
20
+
21
+ Set up your client with the service url:
22
+
23
+ client = MyClient.new("http://localhost:9292")
24
+
25
+ You get all the http verbs as methods, plus a `parse` method that will give you a Hash parsed from JSON:
26
+
27
+ class MyClient < Reverb::Service::Client
28
+ def get_some_stuff
29
+ parse get("/foo", {bar: 'baz'})
30
+ end
31
+ end
32
+
33
+ If the service is down, this will throw an error:
34
+
35
+ Reverb::Service::Client::ServiceUnavailableError
36
+
37
+ That's all (for now).
38
+
39
+ ## Contributing
40
+
41
+ 1. Fork it
42
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
43
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
44
+ 4. Push to the branch (`git push origin my-new-feature`)
45
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,76 @@
1
+ require "typhoeus"
2
+ require "json"
3
+ require 'active_support/all'
4
+ require 'pp'
5
+
6
+ require "reverb/service/client/version"
7
+
8
+ module Reverb
9
+ module Service
10
+ class Client
11
+ class ServiceUnavailableError < RuntimeError; end
12
+ class BadResponseError < RuntimeError; end
13
+ class NotFoundError < RuntimeError; end
14
+
15
+ def initialize(service_url, timeout: 5)
16
+ @service_url = service_url
17
+ @timeout = timeout
18
+ end
19
+
20
+ protected
21
+
22
+ def put(endpoint, body={})
23
+ request(endpoint, 'PUT', body)
24
+ end
25
+
26
+ def get(endpoint, params={})
27
+ request(endpoint_with_params(endpoint, params), 'GET')
28
+ end
29
+
30
+ def post(endpoint, body)
31
+ request(endpoint, 'POST', body)
32
+ end
33
+
34
+ def delete(endpoint, params={})
35
+ request(endpoint_with_params(endpoint, params), 'DELETE')
36
+ end
37
+
38
+ def parse(response)
39
+ return {} if response.body.empty?
40
+ JSON.parse(response.body)
41
+ rescue JSON::ParserError
42
+ raise Reverb::Service::Client::BadResponseError, "Expected a JSON response. Status: #{response.code} Body:#{response.body}"
43
+ end
44
+
45
+ def request(endpoint, method, body=nil)
46
+ request = Typhoeus::Request.new("#{@service_url}/#{endpoint}", {
47
+ method: method,
48
+ timeout: @timeout,
49
+ body: body.to_json,
50
+ forbid_reuse: true, # do not re-use connections in libcurl
51
+ followlocation: true,
52
+ maxredirs: 3, # only follow 3 redirects
53
+ headers: {
54
+ 'Content-Type' => "application/hal+json"
55
+ }
56
+ })
57
+
58
+ request.on_complete do |response|
59
+ if response.timed_out?
60
+ raise Reverb::Service::Client::ServiceUnavailableError, response.pretty_inspect
61
+ end
62
+ end
63
+
64
+ request.run
65
+ end
66
+
67
+ def endpoint_with_params(endpoint, params)
68
+ if !params.empty?
69
+ "#{endpoint}?#{params.to_param}"
70
+ else
71
+ endpoint
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,7 @@
1
+ module Reverb
2
+ module Service
3
+ class Client
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'reverb/service/client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "reverb-service-client"
8
+ spec.version = Reverb::Service::Client::VERSION
9
+ spec.authors = ["Yan Pritzker"]
10
+ spec.email = ["yan@reverb.com"]
11
+ spec.description = %q{Base for http service clients}
12
+ spec.summary = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "typhoeus"
22
+ spec.add_dependency "activesupport"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,77 @@
1
+ require 'reverb/service/client'
2
+ require 'webmock/rspec'
3
+
4
+ describe Reverb::Service::Client do
5
+ let(:url) { "http://some.url"}
6
+ let(:url_with_params) { "#{url}/foo?bar=baz" }
7
+
8
+ class MyClient < Reverb::Service::Client
9
+ def get_test
10
+ parse get("foo", bar: 'baz')
11
+ end
12
+
13
+ def post_test
14
+ post("foo", {bar: "baz"})
15
+ end
16
+
17
+ def delete_test
18
+ delete("foo", bar: "baz")
19
+ end
20
+
21
+ def put_test
22
+ parse put("foo", {bar: "baz"})
23
+ end
24
+ end
25
+
26
+ let(:client) { MyClient.new(url) }
27
+
28
+ it "executes GET requests" do
29
+ stub_request(:GET, url_with_params).to_return(status: 200, body: "{}")
30
+ client.get_test
31
+ end
32
+
33
+ it "executes PUT requests" do
34
+ stub_request(:PUT, "http://some.url/foo").to_return(status: 200, body: "{}")
35
+ client.put_test
36
+ end
37
+
38
+ it "executes DELETE requests" do
39
+ stub_request(:DELETE, url_with_params).to_return(status: 200, body: "{}")
40
+ client.delete_test
41
+ end
42
+
43
+ context "when the response is empty" do
44
+ before do
45
+ stub_request(:GET, url_with_params).to_return(status: 404, body: "")
46
+ end
47
+
48
+ specify do
49
+ client.get_test.should == {}
50
+ end
51
+ end
52
+
53
+ context "when there is a problem parsing the response" do
54
+ before do
55
+ stub_request(:GET, url_with_params).to_return(status: 500, body: "Not json!")
56
+ end
57
+
58
+ specify do
59
+ expect { client.get_test }.to raise_error(Reverb::Service::Client::BadResponseError)
60
+ end
61
+ end
62
+
63
+ context "when the service is down" do
64
+ before do
65
+ stub_request(:GET, url_with_params).to_timeout
66
+ end
67
+
68
+ it "raises a ServiceUnavailableError with typhoeus debugging output as the message" do
69
+ begin
70
+ client.get_test
71
+ rescue Reverb::Service::Client::ServiceUnavailableError => e
72
+ e.message.should be_present
73
+ end
74
+ end
75
+ end
76
+ end
77
+
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reverb-service-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yan Pritzker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: typhoeus
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: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Base for http service clients
70
+ email:
71
+ - yan@reverb.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - lib/reverb/service/client.rb
82
+ - lib/reverb/service/client/version.rb
83
+ - service-client.gemspec
84
+ - spec/client_spec.rb
85
+ homepage: ''
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.0.6
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: ''
109
+ test_files:
110
+ - spec/client_spec.rb