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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +1 -0
- data/lib/reverb/service/client.rb +76 -0
- data/lib/reverb/service/client/version.rb +7 -0
- data/service-client.gemspec +26 -0
- data/spec/client_spec.rb +77 -0
- metadata +110 -0
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
data/Gemfile
ADDED
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,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
|
data/spec/client_spec.rb
ADDED
@@ -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
|