confrater 0.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
+ SHA256:
3
+ metadata.gz: a657e0b6f40bcefaa6e75445c188f3d58219958248dc01ce7aed33db8524524e
4
+ data.tar.gz: 01cdb26c479da1ad3c89f5b8f4f8a64a466e8810760884cd43b41084dbee3ed2
5
+ SHA512:
6
+ metadata.gz: 106feff91b10bc8a688178cfb4bd0a8837602b073b4d2014c0155689270bf57f1218e31443220d51b1306f04db2a55d7c2fed02e9abfd7dda40711f932992090
7
+ data.tar.gz: d86f4dce95ec98cc07e9224c6ad7b29d4b0b990af89f50d498e976b9fb2133db1ea2da03812777a9780cc53ca484b6ab9e8d454f74367066e3b128854dd12f18
@@ -0,0 +1,49 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+
17
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
+ #
19
+ # * Create a file at ~/.gitignore
20
+ # * Include files you want ignored
21
+ # * Run: git config --global core.excludesfile ~/.gitignore
22
+ #
23
+ # After doing this, these files will be ignored in all your git projects,
24
+ # saving you from having to 'pollute' every project you touch with them
25
+ #
26
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
+ #
28
+ # For MacOS:
29
+ #
30
+ .DS_Store
31
+ #
32
+ # For TextMate
33
+ #*.tmproj
34
+ #tmtags
35
+ #
36
+ # For emacs:
37
+ #*~
38
+ #\#*
39
+ #.\#*
40
+ #
41
+ # For vim:
42
+ #*.swp
43
+
44
+ bin
45
+ cache
46
+ gems
47
+ specifications
48
+ Gemfile.lock
49
+ .rvmrc
File without changes
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ platforms :rbx do
4
+ gem 'rubysl'
5
+ gem 'rubinius-developer_tools'
6
+ end
7
+
8
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2017 Espen Antonsen and Amro Mousa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,191 @@
1
+ # Confrere Ruby API Wrapper
2
+
3
+ Confrere is an API wrapper for the [Confrere API](https://developer.confrere.com/).
4
+
5
+ ## Important Notes
6
+
7
+ Confrere returns a `Confrere::Response` instead of the response body directly. `Confrere::Response` exposes the parsed response `body` and `headers`.
8
+
9
+ ## Installation
10
+
11
+ $ gem install confrere
12
+
13
+ ## Authentication
14
+
15
+ The Confrere API authenticates using username and password which you can retrieve from your Confrere account.
16
+
17
+ ## Usage
18
+
19
+ First, create a *one-time use instance* of `Confrere::Request`:
20
+
21
+ ```ruby
22
+ confrere = Confrere::Request.new(username: "your client id", password: "your secret")
23
+ ```
24
+
25
+ ***Note*** Only reuse instances of Confrere after terminating a call with a verb, which makes a request. Requests are light weight objects that update an internal path based on your call chain. When you terminate a call chain with a verb, a request instance makes a request and resets the path.
26
+
27
+ You can set an individual request's `timeout` and `open_timeout` like this:
28
+
29
+ ```ruby
30
+ confrere.timeout = 30
31
+ confrere.open_timeout = 30
32
+ ```
33
+
34
+ You can read about `timeout` and `open_timeout` in the [Net::HTTP](https://ruby-doc.org/stdlib-2.3.3/libdoc/net/http/rdoc/Net/HTTP.html) doc.
35
+
36
+ Now you can make requests using the resources defined in [the Confrere's docs](https://developer.confrere.com/reference). Resource IDs
37
+ are specified inline and a `CRUD` (`create`, `retrieve`, `update`, or `delete`) verb initiates the request.
38
+
39
+ You can specify `headers`, `params`, and `body` when calling a `CRUD` method. For example:
40
+
41
+ ```ruby
42
+ confrere.customers.retrieve(headers: {"SomeHeader": "SomeHeaderValue"}, params: {"query_param": "query_param_value"})
43
+ ```
44
+
45
+ Of course, `body` is only supported on `create` and `update` calls. Those map to HTTP `POST` and `PUT` verbs respectively.
46
+
47
+ You can set `username`, `password`, `api_endpoint`, `timeout`, `open_timeout`, `faraday_adapter`, `proxy`, `symbolize_keys`, `logger`, and `debug` globally:
48
+
49
+ ```ruby
50
+ Confrere::Request.username = "your_client_id"
51
+ Confrere::Request.password = "your_secret"
52
+ Confrere::Request.timeout = 15
53
+ Confrere::Request.open_timeout = 15
54
+ Confrere::Request.symbolize_keys = true
55
+ Confrere::Request.debug = false
56
+ ```
57
+
58
+ For example, you could set the values above in an `initializer` file in your `Rails` app (e.g. your\_app/config/initializers/confrere.rb).
59
+
60
+ Assuming you've set the credentials on Confrere, you can conveniently make API calls on the class itself:
61
+
62
+ ```ruby
63
+ Confrere::Request.customers.retrieve
64
+ ```
65
+
66
+ ***Note*** Substitute an underscore if a resource name contains a hyphen.
67
+
68
+ Pass `symbolize_keys: true` to use symbols (instead of strings) as hash keys in API responses.
69
+
70
+ ```ruby
71
+ confrere = Confrere::Request.new(username: "your_client_id", password: "your_secret", symbolize_keys: true)
72
+ ```
73
+
74
+ Confrere's [API documentation](https://developer.confrere.com/reference) is a list of available endpoints.
75
+
76
+ ## Debug Logging
77
+
78
+ Pass `debug: true` to enable debug logging to STDOUT.
79
+
80
+ ```ruby
81
+ confrere = Confrere::Request.new(username: "your_client_id", password: "your_secret", debug: true)
82
+ ```
83
+
84
+ ### Custom logger
85
+
86
+ Ruby `Logger.new` is used by default, but it can be overrided using:
87
+
88
+ ```ruby
89
+ confrere = Confrere::Request.new(username: "your_client_id", password: "your_secret", debug: true, logger: MyLogger.new)
90
+ ```
91
+
92
+ Logger can be also set by globally:
93
+
94
+ ```ruby
95
+ Confrere::Request.logger = MyLogger.new
96
+ ```
97
+
98
+ ## Examples
99
+
100
+ ### Customers
101
+
102
+ Fetch all customers:
103
+
104
+ ```ruby
105
+ confrere.customers.retrieve
106
+ ```
107
+
108
+ By default the Confrere API returns 50 results. To set the count to 50:
109
+
110
+ ```ruby
111
+ confrere.customers.retrieve(params: {"pagesize": "100"})
112
+ ```
113
+
114
+ And to retrieve the next 50 customers:
115
+
116
+ ```ruby
117
+ confrere.customers.retrieve(params: {"pagesize": "100", "page": "2"})
118
+ ```
119
+
120
+ Query using filters:
121
+
122
+ ```ruby
123
+ confrere.customers.retrieve(params: {"filter": "contains(Name, ‘MakePlans’)"})
124
+ ```
125
+
126
+ Retrieving a specific customer looks like:
127
+
128
+ ```ruby
129
+ confrere.customers(customer_id).retrieve
130
+ ```
131
+
132
+ Add a new customer:
133
+
134
+ ```ruby
135
+ confrere.customers.create(body: {"Name": "MakePlans AS"})
136
+ ```
137
+
138
+ ### Fields
139
+
140
+ Only retrieve ids and names for fetched customers:
141
+
142
+ ```ruby
143
+ confrere.customers.retrieve(params: {"select": "Id, Name"})
144
+ ```
145
+
146
+ ### Error handling
147
+
148
+ Confrere raises an error when the API returns an error.
149
+
150
+ `Confrere::ConfrereError` has the following attributes: `title`, `detail`, `body`, `raw_body`, `status_code`. Some or all of these may not be
151
+ available depending on the nature of the error. For example:
152
+
153
+ ```ruby
154
+ begin
155
+ confrere.customers.create(body: body)
156
+ rescue Confrere::ConfrereError => e
157
+ puts "Houston, we have a problem: #{e.message} - #{e.raw_body}"
158
+ end
159
+ ```
160
+
161
+ ### Other
162
+
163
+ You can set an optional proxy url like this (or with an environment variable CONFRERE_PROXY):
164
+
165
+ ```ruby
166
+ confrere.proxy = 'http://your_proxy.com:80'
167
+ ```
168
+
169
+ You can set a different [Faraday adapter](https://github.com/lostisland/faraday) during initialization:
170
+
171
+ ```ruby
172
+ confrere = Confrere::Request.new(username: "your_client_id", password: "your_secret", faraday_adapter: :net_http)
173
+ ```
174
+
175
+ #### Initialization
176
+
177
+ ```ruby
178
+ confrere = Confrere::Request.new(username: "your_client_id", password: "your_secret")
179
+ ```
180
+
181
+ ## Thanks
182
+
183
+ Thanks to everyone who has [contributed](https://github.com/espen/confrere/contributors) to Confrere's development.
184
+
185
+ ## Credits
186
+
187
+ Based on [Gibbon](https://github.com/amro/gibbon) by [Amro Mousa](https://github.com/amro).
188
+
189
+ ## Copyright
190
+
191
+ * Copyright (c) 2010-2017 Espen Antonsen and Amro Mousa. See LICENSE.txt for details.
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubygems/specification'
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :default => :spec
7
+ desc "Run specs"
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = FileList['spec/**/*_spec.rb']
10
+ t.rspec_opts = %w(-fd --color)
11
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'confrere/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "confrater"
7
+ s.version = Confrere::VERSION
8
+ s.authors = ["Espen Antonsen", "Amro Mousa"]
9
+ s.homepage = "http://github.com/espen/confrere"
10
+
11
+ s.summary = %q{A wrapper for Confrere API}
12
+ s.description = %q{A wrapper for Confrere API}
13
+ s.license = "MIT"
14
+
15
+ s.rubyforge_project = "confrere"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ s.required_ruby_version = '>= 2.0.0'
22
+
23
+ s.add_dependency('faraday')
24
+ s.add_dependency('multi_json')
25
+
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'rspec'
28
+ s.add_development_dependency 'webmock'
29
+
30
+ end
@@ -0,0 +1,13 @@
1
+ require 'faraday'
2
+ require 'multi_json'
3
+ require 'cgi'
4
+ require 'logger'
5
+
6
+ require 'confrere/confrere_error'
7
+ require 'confrere/api_error'
8
+ require 'confrere/request'
9
+ require 'confrere/api_request'
10
+ require 'confrere/response'
11
+
12
+ module Confrere
13
+ end
@@ -0,0 +1,29 @@
1
+ module Confrere
2
+ class APIError < StandardError
3
+ attr_reader :title, :detail, :body, :raw_body, :status_code
4
+
5
+ def initialize(message = "", params = {})
6
+ @title = params[:title]
7
+ @detail = params[:detail]
8
+ @body = params[:body]
9
+ @raw_body = params[:raw_body]
10
+ @status_code = params[:status_code]
11
+
12
+ super(message)
13
+ end
14
+
15
+ def to_s
16
+ super + " " + instance_variables_to_s
17
+ end
18
+
19
+ private
20
+
21
+ def instance_variables_to_s
22
+ [:title, :detail, :body, :raw_body, :status_code].map do |attr|
23
+ attr_value = send(attr)
24
+
25
+ "@#{attr}=#{attr_value.inspect}"
26
+ end.join(", ")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,204 @@
1
+ module Confrere
2
+ class APIRequest
3
+
4
+ def initialize(builder: nil)
5
+ @request_builder = builder
6
+ end
7
+
8
+ def post(params: nil, headers: nil, body: nil)
9
+ ensure_credentials
10
+
11
+ begin
12
+ response = self.rest_client.post do |request|
13
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
14
+ end
15
+ parse_response(response)
16
+ rescue => e
17
+ handle_error(e)
18
+ end
19
+ end
20
+
21
+ def patch(params: nil, headers: nil, body: nil)
22
+ ensure_credentials
23
+
24
+ begin
25
+ response = self.rest_client.patch do |request|
26
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
27
+ end
28
+ parse_response(response)
29
+ rescue => e
30
+ handle_error(e)
31
+ end
32
+ end
33
+
34
+ def put(params: nil, headers: nil, body: nil)
35
+ ensure_credentials
36
+
37
+ begin
38
+ response = self.rest_client.put do |request|
39
+ configure_request(request: request, params: params, headers: headers, body: MultiJson.dump(body))
40
+ end
41
+ parse_response(response)
42
+ rescue => e
43
+ handle_error(e)
44
+ end
45
+ end
46
+
47
+ def get(params: nil, headers: nil)
48
+ ensure_credentials
49
+
50
+ begin
51
+ response = self.rest_client.get do |request|
52
+ configure_request(request: request, params: params, headers: headers)
53
+ end
54
+ parse_response(response)
55
+ rescue => e
56
+ handle_error(e)
57
+ end
58
+ end
59
+
60
+ def delete(params: nil, headers: nil)
61
+ ensure_credentials
62
+
63
+ begin
64
+ response = self.rest_client.delete do |request|
65
+ configure_request(request: request, params: params, headers: headers)
66
+ end
67
+ parse_response(response)
68
+ rescue => e
69
+ handle_error(e)
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ # Convenience accessors
76
+
77
+ def username
78
+ @request_builder.username
79
+ end
80
+
81
+ def password
82
+ @request_builder.password
83
+ end
84
+
85
+ def api_endpoint
86
+ @request_builder.api_endpoint
87
+ end
88
+
89
+ def api_environment
90
+ @request_builder.api_environment
91
+ end
92
+
93
+ def timeout
94
+ @request_builder.timeout
95
+ end
96
+
97
+ def open_timeout
98
+ @request_builder.open_timeout
99
+ end
100
+
101
+ def proxy
102
+ @request_builder.proxy
103
+ end
104
+
105
+ def adapter
106
+ @request_builder.faraday_adapter
107
+ end
108
+
109
+ def symbolize_keys
110
+ @request_builder.symbolize_keys
111
+ end
112
+
113
+ # Helpers
114
+
115
+ def handle_error(error)
116
+ error_params = {}
117
+
118
+ begin
119
+ if error.is_a?(Faraday::Error::ClientError) && error.response
120
+ error_params[:status_code] = error.response[:status]
121
+ error_params[:raw_body] = error.response[:body]
122
+
123
+ parsed_response = MultiJson.load(error.response[:body], symbolize_keys: symbolize_keys)
124
+
125
+ if parsed_response
126
+ error_params[:body] = parsed_response
127
+
128
+ title_key = symbolize_keys ? :title : "title"
129
+ detail_key = symbolize_keys ? :detail : "detail"
130
+
131
+ error_params[:title] = parsed_response[title_key] if parsed_response[title_key]
132
+ error_params[:detail] = parsed_response[detail_key] if parsed_response[detail_key]
133
+ end
134
+
135
+ end
136
+ rescue MultiJson::ParseError
137
+ end
138
+
139
+ error_to_raise = APIError.new(error.message, error_params)
140
+
141
+ raise error_to_raise
142
+ end
143
+
144
+ def configure_request(request: nil, params: nil, headers: nil, body: nil)
145
+ if request
146
+ request.params.merge!(params) if params
147
+ request.headers['Content-Type'] = 'application/json'
148
+ request.headers.merge!(headers) if headers
149
+ request.body = body if body
150
+ request.options.timeout = self.timeout
151
+ request.options.open_timeout = self.open_timeout
152
+ end
153
+ end
154
+
155
+ def rest_client
156
+ client = Faraday.new(self.api_url, proxy: self.proxy, ssl: { version: "TLSv1_2" }) do |faraday|
157
+ faraday.response :raise_error
158
+ faraday.adapter adapter
159
+ if @request_builder.debug
160
+ faraday.response :logger, @request_builder.logger, bodies: true
161
+ end
162
+ end
163
+ client.basic_auth self.username, self.password
164
+ client
165
+ end
166
+
167
+ def parse_response(response)
168
+ parsed_response = nil
169
+
170
+ if response.body && !response.body.empty?
171
+ begin
172
+ headers = response.headers
173
+ body = MultiJson.load(response.body, symbolize_keys: symbolize_keys)
174
+ parsed_response = Response.new(headers: headers, body: body)
175
+ rescue MultiJson::ParseError
176
+ error_params = { title: "UNPARSEABLE_RESPONSE", status_code: 500 }
177
+ error = APIError.new("Unparseable response: #{response.body}", error_params)
178
+ raise error
179
+ end
180
+ end
181
+
182
+ parsed_response
183
+ end
184
+
185
+ def ensure_credentials
186
+ username = self.username
187
+ password = self.password
188
+ unless username && password
189
+ raise Confrere::ConfrereError, "You must set credentials prior to making a call"
190
+ end
191
+ end
192
+
193
+ def api_url
194
+ base_api_url + @request_builder.path
195
+ end
196
+
197
+ def base_api_url
198
+ case @request_builder.api_environment
199
+ when :production
200
+ "https://api.confrere.com/v1/"
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,3 @@
1
+ module Confrere
2
+ class ConfrereError < StandardError; end
3
+ end
@@ -0,0 +1,90 @@
1
+ module Confrere
2
+ class Request
3
+ attr_accessor :username, :password, :api_environment, :api_endpoint, :timeout, :open_timeout, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
4
+
5
+ DEFAULT_TIMEOUT = 60
6
+ DEFAULT_OPEN_TIMEOUT = 60
7
+ DEFAULT_API_ENVIRONMENT = :production
8
+
9
+ def initialize(username: nil, password: nil, api_environment: nil, api_endpoint: nil, timeout: nil, open_timeout: nil, proxy: nil, faraday_adapter: nil, symbolize_keys: false, debug: false, logger: nil)
10
+ @path_parts = []
11
+ @username = username || self.class.username
12
+ @password = password || self.class.password
13
+ @api_environment = api_environment || self.class.api_environment || DEFAULT_API_ENVIRONMENT
14
+ @api_endpoint = api_endpoint || self.class.api_endpoint
15
+ @timeout = timeout || self.class.timeout || DEFAULT_TIMEOUT
16
+ @open_timeout = open_timeout || self.class.open_timeout || DEFAULT_OPEN_TIMEOUT
17
+ @proxy = proxy || self.class.proxy || ENV['CONFRERE_PROXY_URL']
18
+ @faraday_adapter = faraday_adapter || Faraday.default_adapter
19
+ @symbolize_keys = symbolize_keys || self.class.symbolize_keys || false
20
+ @debug = debug || self.class.debug || false
21
+ @logger = logger || self.class.logger || ::Logger.new(STDOUT)
22
+ end
23
+
24
+ def method_missing(method, *args)
25
+ # To support underscores, we replace them with hyphens when calling the API
26
+ @path_parts << method.to_s.gsub("_", "-").downcase
27
+ @path_parts << args if args.length > 0
28
+ @path_parts.flatten!
29
+ self
30
+ end
31
+
32
+ def respond_to_missing?(method_name, include_private = false)
33
+ true
34
+ end
35
+
36
+ def send(*args)
37
+ if args.length == 0
38
+ method_missing(:send, args)
39
+ else
40
+ __send__(*args)
41
+ end
42
+ end
43
+
44
+ def path
45
+ @path_parts.join('/')
46
+ end
47
+
48
+ def create(params: nil, headers: nil, body: nil)
49
+ APIRequest.new(builder: self).post(params: params, headers: headers, body: body)
50
+ ensure
51
+ reset
52
+ end
53
+
54
+ def update(params: nil, headers: nil, body: nil)
55
+ APIRequest.new(builder: self).put(params: params, headers: headers, body: body)
56
+ ensure
57
+ reset
58
+ end
59
+
60
+ def retrieve(params: nil, headers: nil)
61
+ APIRequest.new(builder: self).get(params: params, headers: headers)
62
+ ensure
63
+ reset
64
+ end
65
+
66
+ def delete(params: nil, headers: nil)
67
+ APIRequest.new(builder: self).delete(params: params, headers: headers)
68
+ ensure
69
+ reset
70
+ end
71
+
72
+ protected
73
+
74
+ def reset
75
+ @path_parts = []
76
+ end
77
+
78
+ class << self
79
+ attr_accessor :username, :password, :api_environment, :api_endpoint, :timeout, :open_timeout, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
80
+
81
+ def method_missing(sym, *args, &block)
82
+ new(username: self.username, password: self.password, api_environment: self.api_environment, api_endpoint: self.api_endpoint, timeout: self.timeout, open_timeout: self.open_timeout, faraday_adapter: self.faraday_adapter, symbolize_keys: self.symbolize_keys, debug: self.debug, proxy: self.proxy, logger: self.logger).send(sym, *args, &block)
83
+ end
84
+
85
+ def respond_to_missing?(method_name, include_private = false)
86
+ true
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,10 @@
1
+ module Confrere
2
+ class Response
3
+ attr_accessor :body, :headers
4
+
5
+ def initialize(body: {}, headers: {})
6
+ @body = body
7
+ @headers = headers
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Confrere
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Confrere::APIError do
4
+ let(:message) { 'Foo' }
5
+ let(:params) do
6
+ {
7
+ title: 'error_title',
8
+ detail: 'error_detail',
9
+ body: 'error_body',
10
+ raw_body: 'error_raw_body',
11
+ status_code: 'error_status_code'
12
+ }
13
+ end
14
+
15
+ before do
16
+ @confrere = Confrere::APIError.new(message, params)
17
+ end
18
+
19
+ it "adds the error params to the error message" do
20
+ expected_message = "Foo " \
21
+ "@title=\"error_title\", " \
22
+ "@detail=\"error_detail\", " \
23
+ "@body=\"error_body\", " \
24
+ "@raw_body=\"error_raw_body\", " \
25
+ "@status_code=\"error_status_code\""
26
+
27
+ expect(@confrere.message).to eq(expected_message)
28
+ end
29
+
30
+ it 'sets the title attribute' do
31
+ expect(@confrere.title).to eq(params[:title])
32
+ end
33
+
34
+ it 'sets the detail attribute' do
35
+ expect(@confrere.detail).to eq(params[:detail])
36
+ end
37
+
38
+ it 'sets the body attribute' do
39
+ expect(@confrere.body).to eq(params[:body])
40
+ end
41
+
42
+ it 'sets the raw_body attribute' do
43
+ expect(@confrere.raw_body).to eq(params[:raw_body])
44
+ end
45
+
46
+ it 'sets the status_code attribute' do
47
+ expect(@confrere.status_code).to eq(params[:status_code])
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+
4
+ describe Confrere::APIRequest do
5
+ let(:username) { "42" }
6
+ let(:password) { "hemmelig" }
7
+
8
+ before do
9
+ @confrere = Confrere::Request.new(username: username, password: password)
10
+ @api_root = "https://api.confrere.com/v1"
11
+ end
12
+
13
+ it "surfaces client request exceptions as a Confrere::APIError" do
14
+ exception = Faraday::Error::ClientError.new("the server responded with status 503")
15
+ stub_request(:get, "#{@api_root}/users").with(basic_auth: [username, password]).to_raise(exception)
16
+ expect { @confrere.users.retrieve }.to raise_error(Confrere::APIError)
17
+ end
18
+
19
+ it "surfaces an unparseable client request exception as a Confrere::APIError" do
20
+ exception = Faraday::Error::ClientError.new(
21
+ "the server responded with status 503")
22
+ stub_request(:get, "#{@api_root}/users").with(basic_auth: [username, password]).to_raise(exception)
23
+ expect { @confrere.users.retrieve }.to raise_error(Confrere::APIError)
24
+ end
25
+
26
+ it "surfaces an unparseable response body as a Confrere::APIError" do
27
+ response_values = {:status => 503, :headers => {}, :body => '[foo]'}
28
+ exception = Faraday::Error::ClientError.new("the server responded with status 503", response_values)
29
+ stub_request(:get, "#{@api_root}/users").with(basic_auth: [username, password]).to_raise(exception)
30
+ expect { @confrere.users.retrieve }.to raise_error(Confrere::APIError)
31
+ end
32
+
33
+ context "handle_error" do
34
+ it "includes status and raw body even when json can't be parsed" do
35
+ response_values = {:status => 503, :headers => {}, :body => 'A non JSON response'}
36
+ exception = Faraday::Error::ClientError.new("the server responded with status 503", response_values)
37
+ api_request = Confrere::APIRequest.new(builder: Confrere::Request)
38
+ begin
39
+ api_request.send :handle_error, exception
40
+ rescue => boom
41
+ expect(boom.status_code).to eq 503
42
+ expect(boom.raw_body).to eq "A non JSON response"
43
+ end
44
+ end
45
+
46
+ context "when symbolize_keys is true" do
47
+ it "sets title and detail on the error params" do
48
+ response_values = {:status => 422, :headers => {}, :body => '{"title": "foo", "detail": "bar"}'}
49
+ exception = Faraday::Error::ClientError.new("the server responded with status 422", response_values)
50
+ api_request = Confrere::APIRequest.new(builder: Confrere::Request.new(symbolize_keys: true))
51
+ begin
52
+ api_request.send :handle_error, exception
53
+ rescue => boom
54
+ expect(boom.title).to eq "foo"
55
+ expect(boom.detail).to eq "bar"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,241 @@
1
+ require 'spec_helper'
2
+ require 'cgi'
3
+
4
+ describe Confrere do
5
+ describe "attributes" do
6
+ before do
7
+ Confrere::APIRequest.send(:public, *Confrere::APIRequest.protected_instance_methods)
8
+
9
+ @username = "42"
10
+ @password = "hemmelig"
11
+ @proxy = 'the_proxy'
12
+ end
13
+
14
+ it "have no API by default" do
15
+ @confrere = Confrere::Request.new
16
+ expect(@confrere.username).to be_nil
17
+ end
18
+
19
+ it "sets an API key in the constructor" do
20
+ @confrere = Confrere::Request.new(username: @username, password: @password)
21
+ expect(@confrere.username).to eq(@username)
22
+ expect(@confrere.password).to eq(@password)
23
+ end
24
+
25
+ it "sets an API key via setter" do
26
+ @confrere = Confrere::Request.new
27
+ @confrere.username = @username
28
+ @confrere.password = @password
29
+ expect(@confrere.username).to eq(@username)
30
+ expect(@confrere.password).to eq(@password)
31
+ end
32
+
33
+ it "sets timeout and get" do
34
+ @confrere = Confrere::Request.new
35
+ timeout = 30
36
+ @confrere.timeout = timeout
37
+ expect(timeout).to eq(@confrere.timeout)
38
+ end
39
+
40
+ it "sets the open_timeout and get" do
41
+ @confrere = Confrere::Request.new
42
+ open_timeout = 30
43
+ @confrere.open_timeout = open_timeout
44
+ expect(open_timeout).to eq(@confrere.open_timeout)
45
+ end
46
+
47
+ it "timeout properly passed to APIRequest" do
48
+ @confrere = Confrere::Request.new
49
+ timeout = 30
50
+ @confrere.timeout = timeout
51
+ @request = Confrere::APIRequest.new(builder: @confrere)
52
+ expect(timeout).to eq(@request.timeout)
53
+ end
54
+
55
+ it "timeout properly based on open_timeout passed to APIRequest" do
56
+ @confrere = Confrere::Request.new
57
+ open_timeout = 30
58
+ @confrere.open_timeout = open_timeout
59
+ @request = Confrere::APIRequest.new(builder: @confrere)
60
+ expect(open_timeout).to eq(@request.open_timeout)
61
+ end
62
+
63
+ it "has no Proxy url by default" do
64
+ @confrere = Confrere::Request.new
65
+ expect(@confrere.proxy).to be_nil
66
+ end
67
+
68
+ it "sets an proxy url key from the 'CONFRERE_PROXY_URL' ENV variable" do
69
+ ENV['CONFRERE_PROXY_URL'] = @proxy
70
+ @confrere = Confrere::Request.new
71
+ expect(@confrere.proxy).to eq(@proxy)
72
+ ENV.delete('CONFRERE_PROXY_URL')
73
+ end
74
+
75
+ it "sets an API key via setter" do
76
+ @confrere = Confrere::Request.new
77
+ @confrere.proxy = @proxy
78
+ expect(@confrere.proxy).to eq(@proxy)
79
+ end
80
+
81
+ it "sets an adapter in the constructor" do
82
+ adapter = :em_synchrony
83
+ @confrere = Confrere::Request.new(faraday_adapter: adapter)
84
+ expect(@confrere.faraday_adapter).to eq(adapter)
85
+ end
86
+
87
+ it "symbolize_keys false by default" do
88
+ @confrere = Confrere::Request.new
89
+ expect(@confrere.symbolize_keys).to be false
90
+ end
91
+
92
+ it "sets symbolize_keys in the constructor" do
93
+ @confrere = Confrere::Request.new(symbolize_keys: true)
94
+ expect(@confrere.symbolize_keys).to be true
95
+ end
96
+
97
+ it "sets symbolize_keys in the constructor" do
98
+ @confrere = Confrere::Request.new(symbolize_keys: true)
99
+ expect(@confrere.symbolize_keys).to be true
100
+ end
101
+
102
+ it "debug false by default" do
103
+ @confrere = Confrere::Request.new
104
+ expect(@confrere.debug).to be false
105
+ end
106
+
107
+ it "sets debug in the constructor" do
108
+ @confrere = Confrere::Request.new(debug: true)
109
+ expect(@confrere.debug).to be true
110
+ end
111
+
112
+ it "sets logger in constructor" do
113
+ logger = double(:logger)
114
+ @confrere = Confrere::Request.new(logger: logger)
115
+ expect(@confrere.logger).to eq(logger)
116
+ end
117
+
118
+ it "is a Logger instance by default" do
119
+ @confrere = Confrere::Request.new
120
+ expect(@confrere.logger).to be_a Logger
121
+ end
122
+
123
+ it "api_environment production by default" do
124
+ @confrere = Confrere::Request.new
125
+ expect(@confrere.api_environment).to be :production
126
+ end
127
+
128
+ it "sets api_environment in the constructor" do
129
+ @confrere = Confrere::Request.new(api_environment: :sandbox)
130
+ expect(@confrere.api_environment).to be :sandbox
131
+ end
132
+
133
+ end
134
+
135
+ describe "supports different environments" do
136
+ before do
137
+ Confrere::APIRequest.send(:public, *Confrere::APIRequest.protected_instance_methods)
138
+ end
139
+
140
+ it "has correct api url" do
141
+ @confrere = Confrere::Request.new()
142
+ @request = Confrere::APIRequest.new(builder: @confrere)
143
+ expect(@request.send(:base_api_url)).to eq("https://api.confrere.com/v1/")
144
+ end
145
+
146
+ end
147
+
148
+ describe "build api url" do
149
+ before do
150
+ Confrere::APIRequest.send(:public, *Confrere::APIRequest.protected_instance_methods)
151
+
152
+ @confrere = Confrere::Request.new
153
+ end
154
+
155
+ it "doesn't allow empty api username or password" do
156
+ expect {@confrere.try.retrieve}.to raise_error(Confrere::ConfrereError)
157
+ end
158
+
159
+ end
160
+
161
+ describe "class variables" do
162
+ let(:logger) { double(:logger) }
163
+
164
+ before do
165
+ Confrere::Request.username = "42"
166
+ Confrere::Request.password = "hemmelig"
167
+ Confrere::Request.timeout = 15
168
+ Confrere::Request.api_environment = :sandbox
169
+ Confrere::Request.api_endpoint = 'https://confrere.example.org/v1337/'
170
+ Confrere::Request.logger = logger
171
+ Confrere::Request.proxy = "http://1234.com"
172
+ Confrere::Request.symbolize_keys = true
173
+ Confrere::Request.faraday_adapter = :net_http
174
+ Confrere::Request.debug = true
175
+ end
176
+
177
+ after do
178
+ Confrere::Request.username = nil
179
+ Confrere::Request.password = nil
180
+ Confrere::Request.timeout = nil
181
+ Confrere::Request.api_environment = nil
182
+ Confrere::Request.api_endpoint = nil
183
+ Confrere::Request.logger = nil
184
+ Confrere::Request.proxy = nil
185
+ Confrere::Request.symbolize_keys = nil
186
+ Confrere::Request.faraday_adapter = nil
187
+ Confrere::Request.debug = nil
188
+ end
189
+
190
+ it "set username on new instances" do
191
+ expect(Confrere::Request.new.username).to eq(Confrere::Request.username)
192
+ end
193
+
194
+ it "set password on new instances" do
195
+ expect(Confrere::Request.new.password).to eq(Confrere::Request.password)
196
+ end
197
+
198
+ it "set timeout on new instances" do
199
+ expect(Confrere::Request.new.timeout).to eq(Confrere::Request.timeout)
200
+ end
201
+
202
+ it "set api_environment on new instances" do
203
+ expect(Confrere::Request.api_environment).not_to be_nil
204
+ expect(Confrere::Request.new.api_environment).to eq(Confrere::Request.api_environment)
205
+ end
206
+
207
+ it "set api_endpoint on new instances" do
208
+ expect(Confrere::Request.api_endpoint).not_to be_nil
209
+ expect(Confrere::Request.new.api_endpoint).to eq(Confrere::Request.api_endpoint)
210
+ end
211
+
212
+ it "set proxy on new instances" do
213
+ expect(Confrere::Request.new.proxy).to eq(Confrere::Request.proxy)
214
+ end
215
+
216
+ it "set symbolize_keys on new instances" do
217
+ expect(Confrere::Request.new.symbolize_keys).to eq(Confrere::Request.symbolize_keys)
218
+ end
219
+
220
+ it "set debug on new instances" do
221
+ expect(Confrere::Request.new.debug).to eq(Confrere::Request.debug)
222
+ end
223
+
224
+ it "set faraday_adapter on new instances" do
225
+ expect(Confrere::Request.new.faraday_adapter).to eq(Confrere::Request.faraday_adapter)
226
+ end
227
+
228
+ it "set logger on new instances" do
229
+ expect(Confrere::Request.new.logger).to eq(logger)
230
+ end
231
+ end
232
+
233
+ describe "missing methods" do
234
+ it "respond to .method call on class" do
235
+ expect(Confrere::Request.method(:customers)).to be_a(Method)
236
+ end
237
+ it "respond to .method call on instance" do
238
+ expect(Confrere::Request.new.method(:customers)).to be_a(Method)
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup(:default, :development)
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'confrere'
9
+
10
+ RSpec.configure do |config|
11
+ config.color = true
12
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: confrater
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Espen Antonsen
8
+ - Amro Mousa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-02-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: multi_json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: webmock
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: A wrapper for Confrere API
85
+ email:
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - CHANGELOG.md
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.markdown
95
+ - Rakefile
96
+ - confrere.gemspec
97
+ - lib/confrere.rb
98
+ - lib/confrere/api_error.rb
99
+ - lib/confrere/api_request.rb
100
+ - lib/confrere/confrere_error.rb
101
+ - lib/confrere/request.rb
102
+ - lib/confrere/response.rb
103
+ - lib/confrere/version.rb
104
+ - spec/confrere/api_error_spec.rb
105
+ - spec/confrere/api_request_spec.rb
106
+ - spec/confrere/confrere_spec.rb
107
+ - spec/spec_helper.rb
108
+ homepage: http://github.com/espen/confrere
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: 2.0.0
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubygems_version: 3.0.2
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: A wrapper for Confrere API
131
+ test_files:
132
+ - spec/confrere/api_error_spec.rb
133
+ - spec/confrere/api_request_spec.rb
134
+ - spec/confrere/confrere_spec.rb
135
+ - spec/spec_helper.rb