grac 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,2 @@
1
+ require 'grac/version'
2
+ require 'grac/client'
@@ -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
@@ -0,0 +1,3 @@
1
+ module Grac
2
+ VERSION = "2.0.1"
3
+ end
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: []