grac 2.0.1
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/lib/grac.rb +2 -0
- data/lib/grac/client.rb +132 -0
- data/lib/grac/exception.rb +74 -0
- data/lib/grac/response.rb +39 -0
- data/lib/grac/version.rb +3 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b337c7fac688e4f60d466b5d78cf6929d8cac450
|
4
|
+
data.tar.gz: 6d973b76148b08844fe8055f00f952fdcd581a54
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cc37a4bec5a5c21f58b8cb71f76dafbaf9330c6cce6be5652a0a24ed153128efff2056459b0543494ae19c0fc9016bfc3239a93a02d75d19102ae30a0afb0246
|
7
|
+
data.tar.gz: 196fd93ad92112b1634fc6478a90a35caa98705d6d8efd14bcbe2c44a96dc8ad5378ee1383189fc934f72ec81891f88958e1dfd6aa493a35f42bcfa4b292b9c8
|
data/lib/grac.rb
ADDED
data/lib/grac/client.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'typhoeus'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
require_relative './exception'
|
6
|
+
require_relative './response'
|
7
|
+
|
8
|
+
module Grac
|
9
|
+
class Client
|
10
|
+
attr_reader :uri
|
11
|
+
|
12
|
+
def initialize(uri, options = {})
|
13
|
+
URI.parse(uri)
|
14
|
+
|
15
|
+
@uri = uri
|
16
|
+
@options = {
|
17
|
+
:connecttimeout => options[:connecttimeout] || 0.1,
|
18
|
+
:timeout => options[:timeout] || 15,
|
19
|
+
:params => options[:params] || {},
|
20
|
+
:headers => { "User-Agent" => "Grac v#{Grac::VERSION}" }.merge(options[:headers] || {}),
|
21
|
+
:postprocessing => options[:postprocessing] || {}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(options = {})
|
26
|
+
options = options.merge({
|
27
|
+
headers: @options[:headers].merge(options[:headers] || {})
|
28
|
+
})
|
29
|
+
|
30
|
+
self.class.new(@uri, @options.merge(options))
|
31
|
+
end
|
32
|
+
|
33
|
+
def path(path, variables = {})
|
34
|
+
variables.each do |key, value|
|
35
|
+
path = path.gsub("{#{key}}", value)
|
36
|
+
end
|
37
|
+
self.class.new("#{@uri}#{path}", @options)
|
38
|
+
end
|
39
|
+
|
40
|
+
%w{post put patch}.each do |method|
|
41
|
+
define_method method do |body = {}, params = {}|
|
42
|
+
request = build_request(method, { :body => body, :params => params })
|
43
|
+
run(request)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
%w{get delete}.each do |method|
|
48
|
+
define_method method do |params = {}|
|
49
|
+
request = build_request(method, { :params => params })
|
50
|
+
run(request)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def build_request(method, options = {})
|
56
|
+
body = options[:body].nil? || options[:body].empty? ? nil : options[:body].to_json
|
57
|
+
|
58
|
+
request_hash = { :method => method }
|
59
|
+
request_hash[:params] = @options[:params].merge(options[:params] || {})
|
60
|
+
request_hash[:body] = body
|
61
|
+
request_hash[:connecttimeout] = @options[:connecttimeout]
|
62
|
+
request_hash[:timeout] = @options[:timeout]
|
63
|
+
request_hash[:headers] = @options[:headers]
|
64
|
+
|
65
|
+
return ::Typhoeus::Request.new(uri, request_hash)
|
66
|
+
end
|
67
|
+
|
68
|
+
def postprocessing(data, processing = nil)
|
69
|
+
return data if @options[:postprocessing].nil? || @options[:postprocessing].empty?
|
70
|
+
|
71
|
+
if data.kind_of?(Hash)
|
72
|
+
data.each do |key, value|
|
73
|
+
processing = nil
|
74
|
+
@options[:postprocessing].each do |regex, action|
|
75
|
+
if /#{regex}/ =~ key
|
76
|
+
processing = action
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
data[key] = postprocessing(value, processing)
|
81
|
+
end
|
82
|
+
elsif data.kind_of?(Array)
|
83
|
+
data.each_with_index do |value, index|
|
84
|
+
data[index] = postprocessing(value, processing)
|
85
|
+
end
|
86
|
+
else
|
87
|
+
data = processing.nil? ? data : processing.call(data)
|
88
|
+
end
|
89
|
+
|
90
|
+
return data
|
91
|
+
end
|
92
|
+
|
93
|
+
def run(request)
|
94
|
+
response = request.run
|
95
|
+
|
96
|
+
# Retry GET and HEAD requests - modifying requests might not be idempotent
|
97
|
+
method = request.options[:method].to_s.downcase
|
98
|
+
response = request.run if response.timed_out? && ['get', 'head'].include?(method)
|
99
|
+
|
100
|
+
# A request can time out while receiving data. In this case response.code might indicate
|
101
|
+
# success although data hasn't been fully transferred. Thus rely on Typhoeus for
|
102
|
+
# detecting a timeout.
|
103
|
+
if response.timed_out?
|
104
|
+
raise Exception::ServiceTimeout.new(method, request.url, response.return_message)
|
105
|
+
end
|
106
|
+
|
107
|
+
grac_response = Response.new(response)
|
108
|
+
case response.code
|
109
|
+
when 200, 201
|
110
|
+
if grac_response.json_content?
|
111
|
+
return postprocessing(grac_response.parsed_json)
|
112
|
+
end
|
113
|
+
|
114
|
+
return grac_response.body
|
115
|
+
when 204
|
116
|
+
return true
|
117
|
+
when 0
|
118
|
+
raise Exception::RequestFailed.new(method, request.url, response.return_message)
|
119
|
+
when 400
|
120
|
+
raise Exception::BadRequest.new(method, request.url, grac_response.parsed_or_raw_body)
|
121
|
+
when 403
|
122
|
+
raise Exception::Forbidden.new(method, request.url, grac_response.parsed_or_raw_body)
|
123
|
+
when 404
|
124
|
+
raise Exception::NotFound.new(method, request.url, grac_response.parsed_or_raw_body)
|
125
|
+
when 409
|
126
|
+
raise Exception::Conflict.new(method, request.url, grac_response.parsed_or_raw_body)
|
127
|
+
else
|
128
|
+
raise Exception::ServiceError.new(method, request.url, grac_response.parsed_or_raw_body)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Grac
|
4
|
+
module Exception
|
5
|
+
class ClientException < StandardError
|
6
|
+
attr_reader :url, :method, :body
|
7
|
+
|
8
|
+
def initialize(method, url, body)
|
9
|
+
@method = (method || "").upcase
|
10
|
+
@url = url
|
11
|
+
@body = body
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"#{self.class.name}: #{message}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def message
|
19
|
+
"#{@method} '#{@url}' failed with content: #{@body}"
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :to_s, :message
|
23
|
+
end
|
24
|
+
|
25
|
+
class BadRequest < ClientException; end
|
26
|
+
class Forbidden < ClientException; end
|
27
|
+
class NotFound < ClientException; end
|
28
|
+
class Conflict < ClientException; end
|
29
|
+
class ServiceError < ClientException; end
|
30
|
+
|
31
|
+
class RequestFailed < StandardError
|
32
|
+
attr_reader :method, :url
|
33
|
+
|
34
|
+
def initialize(method, url, message)
|
35
|
+
@method = (method || "").upcase
|
36
|
+
@url = url
|
37
|
+
@message = message
|
38
|
+
end
|
39
|
+
|
40
|
+
def message
|
41
|
+
"#{@method} '#{@url}' failed: #{@message}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
"#{self.class.name}: #{message}"
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :to_s, :message
|
49
|
+
end
|
50
|
+
|
51
|
+
class ServiceTimeout < RequestFailed
|
52
|
+
def message
|
53
|
+
"#{@method} '#{@url}' timed out: #{@message}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class InvalidContent < StandardError
|
58
|
+
def initialize(body, type)
|
59
|
+
@body = body
|
60
|
+
@type = type
|
61
|
+
end
|
62
|
+
|
63
|
+
def message
|
64
|
+
"Failed to parse body as '#{@type}': '#{@body}'"
|
65
|
+
end
|
66
|
+
|
67
|
+
def inspect
|
68
|
+
"#{self.class.name}: #{message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
alias_method :to_s, :message
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require_relative './exception'
|
4
|
+
|
5
|
+
module Grac
|
6
|
+
class Response
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegator :@response, :body
|
10
|
+
|
11
|
+
def initialize(typhoeus_response)
|
12
|
+
@response = typhoeus_response
|
13
|
+
end
|
14
|
+
|
15
|
+
def content_type
|
16
|
+
@response.headers["Content-Type"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def json_content?
|
20
|
+
!content_type.nil? && content_type.match('application/json')
|
21
|
+
end
|
22
|
+
|
23
|
+
def parsed_json
|
24
|
+
JSON.parse(body)
|
25
|
+
rescue JSON::ParserError
|
26
|
+
raise Exception::InvalidContent.new(body, 'json')
|
27
|
+
end
|
28
|
+
|
29
|
+
def parsed_or_raw_body
|
30
|
+
return body unless json_content?
|
31
|
+
|
32
|
+
begin
|
33
|
+
parsed_json
|
34
|
+
rescue Exception::InvalidContent
|
35
|
+
body
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/grac/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grac
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Schoknecht
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 10.4.1
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 10.4.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.2.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.2.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: builder
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.2.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.2.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec_junit_formatter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.2.2
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.2.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack-test
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.6.3
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.6.3
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: typhoeus
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.6.9
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.6.9
|
97
|
+
description: Generic REST API Client
|
98
|
+
email:
|
99
|
+
- tobias.schoknecht@barzahlen.de
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- lib/grac.rb
|
105
|
+
- lib/grac/client.rb
|
106
|
+
- lib/grac/exception.rb
|
107
|
+
- lib/grac/response.rb
|
108
|
+
- lib/grac/version.rb
|
109
|
+
homepage: https://github.com/Barzahlen/grac
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.4.8
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Very generic client for REST API with basic error handling
|
133
|
+
test_files: []
|