chmeetings 0.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/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +16 -0
- data/LICENSE +21 -0
- data/README.md +68 -0
- data/Rakefile +24 -0
- data/chmeetings.gemspec +25 -0
- data/lib/chmeetings/client/campaign.rb +9 -0
- data/lib/chmeetings/client/contribution.rb +13 -0
- data/lib/chmeetings/client/family.rb +25 -0
- data/lib/chmeetings/client/family_member.rb +25 -0
- data/lib/chmeetings/client/group.rb +9 -0
- data/lib/chmeetings/client/person.rb +21 -0
- data/lib/chmeetings/client/pledge.rb +9 -0
- data/lib/chmeetings/client.rb +41 -0
- data/lib/chmeetings/error.rb +58 -0
- data/lib/chmeetings/parse_oj.rb +26 -0
- data/lib/chmeetings/version.rb +5 -0
- data/lib/chmeetings.rb +7 -0
- data/spec/chmeetings/client_spec.rb +115 -0
- data/spec/chmeetings/error_spec.rb +79 -0
- data/spec/chmeetings/resources/campaign_spec.rb +25 -0
- data/spec/chmeetings/resources/contribution_spec.rb +39 -0
- data/spec/chmeetings/resources/family_member_spec.rb +75 -0
- data/spec/chmeetings/resources/family_spec.rb +81 -0
- data/spec/chmeetings/resources/group_spec.rb +25 -0
- data/spec/chmeetings/resources/person_spec.rb +67 -0
- data/spec/chmeetings/resources/pledge_spec.rb +25 -0
- data/spec/chmeetings_spec.rb +7 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/chmeetings_mock.rb +63 -0
- data/spec/support/client_factory.rb +10 -0
- data/spec/support/fixtures/campaigns.json +16 -0
- data/spec/support/fixtures/contribution.json +9 -0
- data/spec/support/fixtures/contributions.json +22 -0
- data/spec/support/fixtures/families.json +14 -0
- data/spec/support/fixtures/family.json +5 -0
- data/spec/support/fixtures/family_member.json +7 -0
- data/spec/support/fixtures/family_members.json +18 -0
- data/spec/support/fixtures/groups.json +16 -0
- data/spec/support/fixtures/people.json +20 -0
- data/spec/support/fixtures/person.json +8 -0
- data/spec/support/fixtures/pledges.json +13 -0
- data/spec/support/fixtures_helper.rb +5 -0
- metadata +117 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 571af7b23e7b7cc9b57dd50b0830952c6bc022626b8fdffd18de96e8f0871683
|
|
4
|
+
data.tar.gz: 13f7aaad4c5af66c26492c0479439026e8edbbc6adb3070b037148ce0098731d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 4bbd3035a3dbed9f7b094d8cf61b7c33c509c0571148734f30d40edfe2eecca4aaf75eca0d9c1675b4a30d87592bc07a360b348bb9257eab95f66c63c352f78d
|
|
7
|
+
data.tar.gz: 2437e3e90b30eef91c985e763566681bbdaf131684c633c62bd1bcc3cda2a9ea132fb07fe59f6b29af852e83452811e1f94a904e3e9b00a6355e56f0ac88eeb3
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.5
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.0.1] - 2026-02-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- A Client class with ApiKey header authentication
|
|
13
|
+
- Methods to list, create, update, and delete people
|
|
14
|
+
- Methods to list, create, get, update, and delete families
|
|
15
|
+
- Methods to list, create, update, patch, and delete family members
|
|
16
|
+
- Methods to list groups
|
|
17
|
+
- Methods to list and create contributions
|
|
18
|
+
- Methods to list pledges
|
|
19
|
+
- Methods to list campaigns
|
data/Gemfile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
gem 'dotenv', '~> 2.8.1'
|
|
8
|
+
gem 'pry', '~> 0.14.2'
|
|
9
|
+
gem 'puma', '~> 6.4'
|
|
10
|
+
gem 'rake', '~> 12.3.3'
|
|
11
|
+
gem 'reek', '~> 6.1'
|
|
12
|
+
gem 'rspec', '~> 3.7'
|
|
13
|
+
gem 'rubocop', '~> 1.57'
|
|
14
|
+
gem 'sinatra', '~> 2.0'
|
|
15
|
+
gem 'webmock', '~> 3.1'
|
|
16
|
+
gem 'yard', '~> 0.9'
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Taylor Brooks
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Chmeetings
|
|
2
|
+
|
|
3
|
+
A Ruby wrapper for the [ChMeetings API](https://api.chmeetings.com/).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'chmeetings'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install chmeetings
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
client = Chmeetings::Client.new(api_key: 'your_api_key')
|
|
25
|
+
|
|
26
|
+
# People
|
|
27
|
+
client.list_people
|
|
28
|
+
client.create_person(first_name: 'John', last_name: 'Doe')
|
|
29
|
+
client.update_person(person_id: 1, first_name: 'Jane')
|
|
30
|
+
client.delete_person(person_id: 1)
|
|
31
|
+
|
|
32
|
+
# Families
|
|
33
|
+
client.list_families
|
|
34
|
+
client.create_family(name: 'Doe Family')
|
|
35
|
+
client.get_family(family_id: 1)
|
|
36
|
+
client.update_family(family_id: 1, name: 'Smith Family')
|
|
37
|
+
client.delete_family(family_id: 1)
|
|
38
|
+
|
|
39
|
+
# Family Members
|
|
40
|
+
client.list_family_members(family_id: 1)
|
|
41
|
+
client.create_family_member(family_id: 1, person_id: 1)
|
|
42
|
+
client.update_family_member(id: 1, family_id: 1, person_id: 2)
|
|
43
|
+
client.patch_family_member(id: 1, role: 'Head')
|
|
44
|
+
client.delete_family_member(id: 1)
|
|
45
|
+
|
|
46
|
+
# Groups
|
|
47
|
+
client.list_groups
|
|
48
|
+
|
|
49
|
+
# Contributions
|
|
50
|
+
client.list_contributions
|
|
51
|
+
client.create_contribution(person_id: 1, amount: 100.0)
|
|
52
|
+
|
|
53
|
+
# Pledges
|
|
54
|
+
client.list_pledges
|
|
55
|
+
|
|
56
|
+
# Campaigns
|
|
57
|
+
client.list_campaigns
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
You can also configure the client using the `CHMEETINGS_API_KEY` environment variable:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
client = Chmeetings::Client.new
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
require 'rspec/core/rake_task'
|
|
3
|
+
|
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
5
|
+
|
|
6
|
+
task default: :spec
|
|
7
|
+
|
|
8
|
+
task :environment do
|
|
9
|
+
require 'dotenv'
|
|
10
|
+
Dotenv.load
|
|
11
|
+
|
|
12
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
|
13
|
+
require 'chmeetings'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc 'Launch a pry shell with libraries loaded'
|
|
17
|
+
task pry: :environment do
|
|
18
|
+
options = {}
|
|
19
|
+
options[:logger] = Logger.new($stdout) unless ENV['CLIENT_LOGGER'].nil?
|
|
20
|
+
@client = Chmeetings::Client.new(**options) if ENV['CHMEETINGS_API_KEY']
|
|
21
|
+
|
|
22
|
+
require 'pry'
|
|
23
|
+
Pry.start
|
|
24
|
+
end
|
data/chmeetings.gemspec
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'English'
|
|
2
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
|
3
|
+
require 'chmeetings/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'chmeetings'
|
|
7
|
+
s.version = Chmeetings::VERSION
|
|
8
|
+
s.authors = ['Taylor Brooks']
|
|
9
|
+
s.homepage = 'https://github.com/taylorbrooks/chmeetings'
|
|
10
|
+
s.summary = 'A Ruby wrapper for the ChMeetings API'
|
|
11
|
+
s.description = 'A Ruby wrapper for the ChMeetings API'
|
|
12
|
+
s.license = 'MIT'
|
|
13
|
+
|
|
14
|
+
s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
15
|
+
s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
16
|
+
|
|
17
|
+
s.required_ruby_version = '>= 2.7'
|
|
18
|
+
|
|
19
|
+
s.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
s.add_runtime_dependency 'faraday', '> 2.0'
|
|
22
|
+
s.add_runtime_dependency 'oj'
|
|
23
|
+
|
|
24
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Chmeetings
|
|
2
|
+
class Client
|
|
3
|
+
module Family
|
|
4
|
+
def list_families(**options)
|
|
5
|
+
get('families', options)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def create_family(**data)
|
|
9
|
+
post('families', data)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_family(**options)
|
|
13
|
+
get('families/show', options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def update_family(**data)
|
|
17
|
+
put('families', data)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def delete_family(**data)
|
|
21
|
+
post('families/delete', data)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Chmeetings
|
|
2
|
+
class Client
|
|
3
|
+
module FamilyMember
|
|
4
|
+
def list_family_members(**options)
|
|
5
|
+
get('family-members', options)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def create_family_member(**data)
|
|
9
|
+
post('family-members', data)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def update_family_member(**data)
|
|
13
|
+
put('family-members', data)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def patch_family_member(**data)
|
|
17
|
+
patch('family-members', data)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def delete_family_member(**data)
|
|
21
|
+
post('family-members/delete', data)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Chmeetings
|
|
2
|
+
class Client
|
|
3
|
+
module Person
|
|
4
|
+
def list_people(**options)
|
|
5
|
+
get('people', options)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def create_person(**data)
|
|
9
|
+
post('people', data)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def update_person(**data)
|
|
13
|
+
put('people', data)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def delete_person(**data)
|
|
17
|
+
post('people/delete', data)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
|
|
3
|
+
Dir[File.expand_path('client/*.rb', __dir__)].sort.each { |f| require f }
|
|
4
|
+
|
|
5
|
+
module Chmeetings
|
|
6
|
+
class Client
|
|
7
|
+
include Person
|
|
8
|
+
include Family
|
|
9
|
+
include FamilyMember
|
|
10
|
+
include Group
|
|
11
|
+
include Contribution
|
|
12
|
+
include Pledge
|
|
13
|
+
include Campaign
|
|
14
|
+
|
|
15
|
+
def initialize(**config)
|
|
16
|
+
@api_key = config[:api_key] || ENV.fetch('CHMEETINGS_API_KEY', nil)
|
|
17
|
+
@base_url = config[:base_url] || 'https://api.chmeetings.com/api/v1/'
|
|
18
|
+
@logger = config[:logger]
|
|
19
|
+
@adapter = config[:adapter] || Faraday.default_adapter
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
[:get, :post, :delete, :patch, :put].each do |http_method|
|
|
23
|
+
define_method(http_method) do |path, body = {}|
|
|
24
|
+
connection.public_send(http_method, path, body).body
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def connection
|
|
31
|
+
Faraday.new(url: @base_url) do |conn|
|
|
32
|
+
conn.headers['ApiKey'] = @api_key
|
|
33
|
+
conn.request :json
|
|
34
|
+
conn.response :chmeetings_oj
|
|
35
|
+
conn.response :logger, @logger if @logger
|
|
36
|
+
conn.use Chmeetings::FaradayMiddleware::ChmeetingsErrorHandler
|
|
37
|
+
conn.adapter @adapter
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
|
|
3
|
+
module Chmeetings # :nodoc: all
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
class BadGateway < Error; end
|
|
6
|
+
class BadRequest < Error; end
|
|
7
|
+
class CloudflareError < Error; end
|
|
8
|
+
class Forbidden < Error; end
|
|
9
|
+
class GatewayTimeout < Error; end
|
|
10
|
+
class InternalServerError < Error; end
|
|
11
|
+
class NotFound < Error; end
|
|
12
|
+
class ServiceUnavailable < Error; end
|
|
13
|
+
class TooManyRequests < Error; end
|
|
14
|
+
class Unauthorized < Error; end
|
|
15
|
+
|
|
16
|
+
module FaradayMiddleware
|
|
17
|
+
class ChmeetingsErrorHandler < Faraday::Middleware
|
|
18
|
+
ERROR_STATUSES = (400..600).freeze
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Throws an exception for responses with an HTTP error code.
|
|
22
|
+
def on_complete(env)
|
|
23
|
+
message = error_message(env)
|
|
24
|
+
|
|
25
|
+
case env[:status]
|
|
26
|
+
when 400
|
|
27
|
+
raise Chmeetings::BadRequest, message
|
|
28
|
+
when 401
|
|
29
|
+
raise Chmeetings::Unauthorized, message
|
|
30
|
+
when 403
|
|
31
|
+
raise Chmeetings::Forbidden, message
|
|
32
|
+
when 404
|
|
33
|
+
raise Chmeetings::NotFound, message
|
|
34
|
+
when 429
|
|
35
|
+
raise Chmeetings::TooManyRequests, message
|
|
36
|
+
when 500
|
|
37
|
+
raise Chmeetings::InternalServerError, message
|
|
38
|
+
when 502
|
|
39
|
+
raise Chmeetings::BadGateway, message
|
|
40
|
+
when 503
|
|
41
|
+
raise Chmeetings::ServiceUnavailable, message
|
|
42
|
+
when 504
|
|
43
|
+
raise Chmeetings::GatewayTimeout, message
|
|
44
|
+
when 520
|
|
45
|
+
raise Chmeetings::CloudflareError, message
|
|
46
|
+
when ERROR_STATUSES
|
|
47
|
+
raise Chmeetings::Error, message
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def error_message(env)
|
|
54
|
+
"#{env[:status]}: #{env[:url]} #{env[:body]}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'oj'
|
|
2
|
+
|
|
3
|
+
module Chmeetings
|
|
4
|
+
module FaradayMiddleware
|
|
5
|
+
class ParseOj < Faraday::Middleware
|
|
6
|
+
##
|
|
7
|
+
# Parses JSON responses.
|
|
8
|
+
def on_complete(env)
|
|
9
|
+
body = env[:body]
|
|
10
|
+
env[:body] = if empty_body?(body.strip)
|
|
11
|
+
nil
|
|
12
|
+
else
|
|
13
|
+
Oj.load(body, mode: :compat)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def empty_body?(body)
|
|
20
|
+
body.empty? && body == ''
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Faraday::Response.register_middleware(chmeetings_oj: Chmeetings::FaradayMiddleware::ParseOj)
|
data/lib/chmeetings.rb
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Chmeetings::Client do
|
|
4
|
+
let(:attrs) { { api_key: 'test_api_key' } }
|
|
5
|
+
|
|
6
|
+
subject(:client) { described_class.new(**attrs) }
|
|
7
|
+
|
|
8
|
+
shared_examples 'param request' do |verb|
|
|
9
|
+
let(:endpoint) { "#{verb}_test" }
|
|
10
|
+
let(:url) { "https://api.chmeetings.com/api/v1/#{endpoint}" }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
stub_request(:any, /_test/).to_return(body: response_body.to_json)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'requests at `path` argument' do
|
|
17
|
+
client.public_send(verb, endpoint)
|
|
18
|
+
|
|
19
|
+
expect(WebMock).to have_requested(verb, url)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'passes request parameters' do
|
|
23
|
+
client.public_send(verb, endpoint, request_params)
|
|
24
|
+
|
|
25
|
+
expect(WebMock).to have_requested(verb, url).with(query: request_params)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'returns parsed response body' do
|
|
29
|
+
expect(client.public_send(verb, endpoint)).to eq(response_body)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
shared_examples 'body request' do |verb|
|
|
34
|
+
let(:body) { { 'test' => 123 } }
|
|
35
|
+
let(:endpoint) { "#{verb}_test" }
|
|
36
|
+
let(:url) { "https://api.chmeetings.com/api/v1/#{endpoint}" }
|
|
37
|
+
|
|
38
|
+
let(:do_request) { client.public_send(verb, endpoint, body) }
|
|
39
|
+
|
|
40
|
+
before do
|
|
41
|
+
stub_request(:any, /_test/).to_return(body: body.to_json)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'requests at `path` argument' do
|
|
45
|
+
do_request
|
|
46
|
+
|
|
47
|
+
expect(WebMock).to have_requested(verb, url)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'passes request body' do
|
|
51
|
+
do_request
|
|
52
|
+
|
|
53
|
+
expect(WebMock)
|
|
54
|
+
.to have_requested(verb, url)
|
|
55
|
+
.with(body: body)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'returns parsed response body' do
|
|
59
|
+
expect(do_request).to eq(body)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe 'authentication' do
|
|
64
|
+
let(:path) { 'people' }
|
|
65
|
+
let(:url) { "https://api.chmeetings.com/api/v1/#{path}" }
|
|
66
|
+
|
|
67
|
+
it 'sends the ApiKey header' do
|
|
68
|
+
client.get(path)
|
|
69
|
+
|
|
70
|
+
expect(WebMock).to have_requested(:get, url)
|
|
71
|
+
.with(headers: { 'ApiKey' => 'test_api_key' })
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe 'env var authentication' do
|
|
76
|
+
let(:attrs) { {} }
|
|
77
|
+
|
|
78
|
+
before do
|
|
79
|
+
allow(ENV).to receive(:fetch).with('CHMEETINGS_API_KEY', nil).and_return('env_api_key')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'uses CHMEETINGS_API_KEY env var' do
|
|
83
|
+
client.get('people')
|
|
84
|
+
|
|
85
|
+
expect(WebMock).to have_requested(:get, 'https://api.chmeetings.com/api/v1/people')
|
|
86
|
+
.with(headers: { 'ApiKey' => 'env_api_key' })
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe '#get(path, options = {})' do
|
|
91
|
+
let(:request_params) { { 'test' => 123 } }
|
|
92
|
+
let(:response_body) { request_params }
|
|
93
|
+
|
|
94
|
+
include_examples 'param request', :get
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '#delete(path, options = {})' do
|
|
98
|
+
let(:request_params) { { 'test' => 123 } }
|
|
99
|
+
let(:response_body) { {} }
|
|
100
|
+
|
|
101
|
+
include_examples 'param request', :delete
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe '#patch(path, options = {})' do
|
|
105
|
+
include_examples 'body request', :patch
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe '#post(path, options = {})' do
|
|
109
|
+
include_examples 'body request', :post
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe '#put(path, options = {})' do
|
|
113
|
+
include_examples 'body request', :put
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'rack/utils'
|
|
3
|
+
|
|
4
|
+
CODES = Rack::Utils::HTTP_STATUS_CODES.keys.freeze
|
|
5
|
+
|
|
6
|
+
RSpec.describe Chmeetings::Error do
|
|
7
|
+
let(:client) do
|
|
8
|
+
Chmeetings::Client.new(
|
|
9
|
+
base_url: 'http://some-chmeetings-uri.com/api/v1/',
|
|
10
|
+
api_key: 'test_api_key'
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def stub(code, body)
|
|
15
|
+
stub_request(:any, /chmeetings/).to_return(status: code, body: body)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def expect_failure(code, body)
|
|
19
|
+
url = 'http://some-chmeetings-uri.com/api/v1/anything'
|
|
20
|
+
|
|
21
|
+
expect do
|
|
22
|
+
client.get('anything')
|
|
23
|
+
end.to raise_error(Chmeetings::Error, /#{code}: #{url} #{body}/)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def expect_success
|
|
27
|
+
expect { client.get('anything') }.to_not raise_error
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'informational responses' do
|
|
31
|
+
CODES.grep(100..199).each do |code|
|
|
32
|
+
it "does not raise error for #{code}" do
|
|
33
|
+
stub(code, '{}')
|
|
34
|
+
expect_success
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'success responses' do
|
|
40
|
+
CODES.grep(200..299).each do |code|
|
|
41
|
+
it "does not raise error for #{code}" do
|
|
42
|
+
stub(code, '{}')
|
|
43
|
+
expect_success
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'redirection responses' do
|
|
49
|
+
CODES.grep(300..399).each do |code|
|
|
50
|
+
it "does not raise error for #{code}" do
|
|
51
|
+
stub(code, '')
|
|
52
|
+
expect_success
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'client error responses' do
|
|
58
|
+
CODES.grep(400..499).each do |code|
|
|
59
|
+
it "raises exception for #{code}" do
|
|
60
|
+
stub(code, 'test client error')
|
|
61
|
+
expect_failure(code, 'test client error')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'server error responses' do
|
|
67
|
+
CODES.grep(500..599).each do |code|
|
|
68
|
+
it "raises exception for #{code}" do
|
|
69
|
+
stub(code, 'test client error')
|
|
70
|
+
expect_failure(code, 'test client error')
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'raises TooManyRequests for 429' do
|
|
76
|
+
stub(429, 'rate limited')
|
|
77
|
+
expect { client.get('anything') }.to raise_error(Chmeetings::TooManyRequests)
|
|
78
|
+
end
|
|
79
|
+
end
|