api_base 0.1.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 +12 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/api_base.gemspec +33 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/db/migrate/20220612165032_create_api_logs.rb +20 -0
- data/lib/api_base/base.rb +70 -0
- data/lib/api_base/behaviours/get_json.rb +26 -0
- data/lib/api_base/behaviours/post_json.rb +27 -0
- data/lib/api_base/behaviours/shared.rb +51 -0
- data/lib/api_base/concerns/filterer.rb +47 -0
- data/lib/api_base/concerns/traceable.rb +25 -0
- data/lib/api_base/models/api_log.rb +109 -0
- data/lib/api_base/version.rb +3 -0
- data/lib/api_base.rb +12 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f7c64a64a166f1c8b54d6d06d7d390c42d38166dead3e70574097cc98f7c1553
|
4
|
+
data.tar.gz: 62c43b1db2628f41c1817e1f2700eaf9b4cf38e6ec94ec77fd4620e6a37e7f7b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 737062be042509aa0ea003d0327ed429614a4aa068555392c8d7c48bf73e2551dccdbfba6ea54c13174354ef88de669b1bc9df26eaefef88ed12463f3adbe010
|
7
|
+
data.tar.gz: 1e9bc490d4c224c55bbb2b0f086d235601bebdc99e0ab6b3907d4ca7da9d7c6931b6b924c7a28f59f1b442bf3e7adbb20220a88a5bd4b3378385a4b6ad05a1f9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Stefan Froelich
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# ApiBase
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/api_base`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'api_base'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install api_base
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/api_base.
|
36
|
+
|
37
|
+
|
38
|
+
## License
|
39
|
+
|
40
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/api_base.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative "lib/api_base/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "api_base"
|
5
|
+
spec.version = ApiBase::VERSION
|
6
|
+
spec.authors = ["Stefan Froelich"]
|
7
|
+
spec.email = ["sfroelich01@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = "Building blocks for building API Clients"
|
10
|
+
spec.description = spec.summary
|
11
|
+
spec.homepage = "https://github.com/ussd-engine/api-base"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
|
+
|
15
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
+
spec.metadata["changelog_uri"] = spec.homepage
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_dependency "rails", "~> 7"
|
31
|
+
spec.add_dependency "faraday", "~> 2"
|
32
|
+
spec.add_dependency "stoplight", "~> 3"
|
33
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "api_base"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateApiLogs < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
create_table :api_logs do |t|
|
4
|
+
t.text :api, null: false
|
5
|
+
t.text :origin, null: false
|
6
|
+
t.text :source, null: false
|
7
|
+
t.text :endpoint, null: false
|
8
|
+
t.text :method, null: false
|
9
|
+
t.jsonb :request_headers
|
10
|
+
t.jsonb :request_body
|
11
|
+
t.integer :status_code
|
12
|
+
t.jsonb :response_headers
|
13
|
+
t.jsonb :response_body
|
14
|
+
t.float :duration
|
15
|
+
t.jsonb :exception
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "faraday"
|
3
|
+
require "stoplight"
|
4
|
+
require "api_base/concerns/traceable"
|
5
|
+
require "api_base/concerns/filterer"
|
6
|
+
|
7
|
+
module ApiBase
|
8
|
+
class Base
|
9
|
+
include ActiveSupport::Rescuable
|
10
|
+
include Concerns::Traceable
|
11
|
+
include Concerns::Filterer
|
12
|
+
|
13
|
+
def identifier
|
14
|
+
raise NotImplementedError, "identifier is not implemented"
|
15
|
+
end
|
16
|
+
|
17
|
+
def connection
|
18
|
+
raise NotImplementedError, "connection is not implemented"
|
19
|
+
end
|
20
|
+
|
21
|
+
def sensitive_data_keys
|
22
|
+
raise NotImplementedError, "sensitive_data_keys is not implemented"
|
23
|
+
end
|
24
|
+
|
25
|
+
rescue_from Stoplight::Error::RedLight do
|
26
|
+
Rails.logger.warn "#{identifier} api circuit is closed"
|
27
|
+
raise Api::Error::ApiError, "Circuit broken"
|
28
|
+
end
|
29
|
+
|
30
|
+
rescue_from Faraday::TimeoutError do
|
31
|
+
Rails.logger.warn "#{identifier} api timed-out"
|
32
|
+
raise Api::Error::ApiError, "Request timed-out"
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def execute(&block)
|
38
|
+
light = Stoplight(identifier) do
|
39
|
+
block.call
|
40
|
+
end
|
41
|
+
|
42
|
+
light.with_error_handler do |error, handler|
|
43
|
+
# We don't want processing errors to affect our circuit breakers
|
44
|
+
# They are our api equivalent of runtime errors.
|
45
|
+
raise error if error.is_a?(Api::Error::ProcessingError)
|
46
|
+
|
47
|
+
handler.call(error)
|
48
|
+
end
|
49
|
+
|
50
|
+
light.run
|
51
|
+
rescue StandardError => e
|
52
|
+
trace_active_error(e)
|
53
|
+
rescue_with_handler(e) || raise
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_status_code(response)
|
57
|
+
return if success_status_codes.include?(response.status)
|
58
|
+
|
59
|
+
raise Api::Error::ProcessingError, "Request failed with status: #{response.status}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def success_status_codes
|
63
|
+
[200, 201]
|
64
|
+
end
|
65
|
+
|
66
|
+
def filterer
|
67
|
+
@filterer ||= ActiveSupport::ParameterFilter.new sensitive_data_keys
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiBase
|
4
|
+
module Behaviours
|
5
|
+
# Shared concern that adds the ability to get json from an endpoint
|
6
|
+
module GetJson
|
7
|
+
include Shared
|
8
|
+
|
9
|
+
alias get_json behaviour_delegate
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def execute_request(endpoint, _payload)
|
14
|
+
execute do
|
15
|
+
connection.get(endpoint) do |req|
|
16
|
+
req.headers["Content-Type"] = "application/json"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def method
|
22
|
+
"GET"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiBase
|
4
|
+
module Behaviours
|
5
|
+
# Shared concern that adds the ability to post json to an endpoint
|
6
|
+
module PostJson
|
7
|
+
include Shared
|
8
|
+
|
9
|
+
alias post_json behaviour_delegate
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def execute_request(endpoint, payload)
|
14
|
+
execute do
|
15
|
+
connection.post(endpoint, payload) do |req|
|
16
|
+
req.body = payload.to_json
|
17
|
+
req.headers["Content-Type"] = "application/json"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def method
|
23
|
+
"POST"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiBase
|
4
|
+
module Behaviours
|
5
|
+
# Shared module that adds common methods to api behaviours
|
6
|
+
module Shared
|
7
|
+
def behaviour_delegate(endpoint, payload = {})
|
8
|
+
api_log = Models::ApiLog.start_outgoing_request(self, method, endpoint, payload)
|
9
|
+
response, duration = make_request(endpoint, payload)
|
10
|
+
api_log.complete_outgoing_request response, duration
|
11
|
+
|
12
|
+
response
|
13
|
+
rescue StandardError => e
|
14
|
+
api_log.exception = e if api_log.present?
|
15
|
+
raise
|
16
|
+
ensure
|
17
|
+
if api_log.present?
|
18
|
+
api_log.filter_sensitive_data { |data| filter_object(data) }
|
19
|
+
api_log.save!
|
20
|
+
end
|
21
|
+
|
22
|
+
validate_status_code response if response.present?
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def make_request(endpoint, payload)
|
28
|
+
trace_active_tag("request.endpoint", endpoint)
|
29
|
+
trace_active_tag("request.payload", filter_object(payload))
|
30
|
+
|
31
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
32
|
+
response = execute_request(endpoint, payload)
|
33
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
34
|
+
|
35
|
+
trace_active_tag("response.status", response.status)
|
36
|
+
trace_active_tag("response.body", filter_object(response.body))
|
37
|
+
trace_active_tag("response.duration", duration)
|
38
|
+
|
39
|
+
[response, duration]
|
40
|
+
end
|
41
|
+
|
42
|
+
def method
|
43
|
+
raise NotImplementedError, "method is not implemented"
|
44
|
+
end
|
45
|
+
|
46
|
+
def execute_request
|
47
|
+
raise NotImplementedError, "execute_request is not implemented"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiBase
|
4
|
+
module Concerns
|
5
|
+
module Filterer
|
6
|
+
protected
|
7
|
+
|
8
|
+
def filterer
|
9
|
+
@filterer ||= ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
|
10
|
+
end
|
11
|
+
|
12
|
+
def filter_object(obj)
|
13
|
+
return if obj.nil?
|
14
|
+
|
15
|
+
case obj
|
16
|
+
when Array then filter_array(obj)
|
17
|
+
when Hash then filter_hash(obj)
|
18
|
+
else obj
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def filter_array(array)
|
23
|
+
return if array.nil?
|
24
|
+
|
25
|
+
array.map do |item|
|
26
|
+
case item
|
27
|
+
when Array then filter_array(item)
|
28
|
+
when Hash then filter_hash(item)
|
29
|
+
else item
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def filter_hash(hash)
|
35
|
+
return if hash.nil?
|
36
|
+
|
37
|
+
hash.each do |key, value|
|
38
|
+
case value
|
39
|
+
when Array then hash[key] = filter_array(value)
|
40
|
+
when Hash then hash[key] = filter_hash(value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
filterer.filter (hash.try(:permit!) || hash).to_hash
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiBase
|
4
|
+
module Concerns
|
5
|
+
module Traceable
|
6
|
+
protected
|
7
|
+
|
8
|
+
def trace_root_tag(name, value)
|
9
|
+
Rails.logger.debug "trace_root_tag -> #{name} | #{value}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def trace_root_error(error)
|
13
|
+
Rails.logger.debug "trace_root_error -> #{error}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def trace_active_tag(name, value)
|
17
|
+
Rails.logger.debug "trace_active_tag -> #{name} | #{value}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def trace_active_error(error)
|
21
|
+
Rails.logger.debug "trace_active_error -> #{error}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: api_logs
|
4
|
+
#
|
5
|
+
# id :bigint not null, primary key
|
6
|
+
# api :text not null
|
7
|
+
# duration :float
|
8
|
+
# endpoint :text not null
|
9
|
+
# exception :jsonb
|
10
|
+
# method :text not null
|
11
|
+
# origin :text not null
|
12
|
+
# request_body :jsonb
|
13
|
+
# request_headers :jsonb
|
14
|
+
# response_body :jsonb
|
15
|
+
# response_headers :jsonb
|
16
|
+
# source :text not null
|
17
|
+
# status_code :integer
|
18
|
+
# created_at :datetime not null
|
19
|
+
# updated_at :datetime not null
|
20
|
+
#
|
21
|
+
require "English"
|
22
|
+
require "active_record"
|
23
|
+
|
24
|
+
module ApiBase
|
25
|
+
module Models
|
26
|
+
class ApiLog < ActiveRecord::Base
|
27
|
+
attribute :sanitized, :boolean, default: false
|
28
|
+
|
29
|
+
validate :nothing_changed, unless: :new_record?
|
30
|
+
validate :data_sanitized
|
31
|
+
|
32
|
+
validates_presence_of :api, :origin, :source, :endpoint
|
33
|
+
|
34
|
+
validates :source, presence: true, inclusion: { in: %w[outgoing_request incoming_webhook] }
|
35
|
+
validates :method, presence: true, inclusion: { in: %w[GET POST DELETE PUT] }
|
36
|
+
|
37
|
+
def self.start_outgoing_request(origin, method, endpoint, payload)
|
38
|
+
ApiLog.new api: origin.identifier, origin: origin.class.to_s, source: "outgoing_request",
|
39
|
+
endpoint: "#{origin.connection.url_prefix}#{endpoint}", method: method,
|
40
|
+
request_headers: origin.connection.headers, request_body: payload
|
41
|
+
end
|
42
|
+
|
43
|
+
def complete_outgoing_request(response, duration)
|
44
|
+
# Ensure we are recording the actual headers that were sent on the request.
|
45
|
+
# The ones set from the connection might not be the final headers.
|
46
|
+
self.request_headers = response.env.request_headers
|
47
|
+
# Set the rest of the response attributes.
|
48
|
+
assign_attributes status_code: response.status, duration: duration,
|
49
|
+
response_body: response.body, response_headers: response.headers
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.start_weekhook_request(origin, request)
|
53
|
+
ApiLog.new api: origin, origin: origin.class.to_s, source: "incoming_webhook",
|
54
|
+
endpoint: request.fullpath, method: request.method,
|
55
|
+
request_headers: request.headers.env.reject { |key|
|
56
|
+
key.to_s.include?(".")
|
57
|
+
}, request_body: request.params
|
58
|
+
end
|
59
|
+
|
60
|
+
def complete_webhook_request(response, duration)
|
61
|
+
# Set the rest of the response attributes.
|
62
|
+
assign_attributes status_code: response.status, duration: duration,
|
63
|
+
response_body: response.body, response_headers: response.headers
|
64
|
+
end
|
65
|
+
|
66
|
+
def filter_sensitive_data
|
67
|
+
parse_json_fields
|
68
|
+
|
69
|
+
%i[request_headers request_body response_headers response_body exception].each do |prop|
|
70
|
+
self[prop] = yield(self[prop]) if self[prop].is_a?(Hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
self.sanitized = true
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def nothing_changed
|
79
|
+
errors.add(:base, "Record is read-only") if changed?
|
80
|
+
end
|
81
|
+
|
82
|
+
def data_sanitized
|
83
|
+
errors.add(:base, "Data must be sanitized") unless sanitized?
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_json_fields
|
87
|
+
%i[request_headers request_body response_headers response_body exception].each do |prop|
|
88
|
+
self[prop] = safely_parse_json(self[prop])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def safely_parse_json(value)
|
93
|
+
case value
|
94
|
+
when nil, Hash
|
95
|
+
value
|
96
|
+
when String
|
97
|
+
JSON.parse value
|
98
|
+
when StandardError
|
99
|
+
[e.message, *e.backtrace].join($INPUT_RECORD_SEPARATOR).to_json
|
100
|
+
else
|
101
|
+
value.to_s.to_json
|
102
|
+
end
|
103
|
+
rescue StandardError
|
104
|
+
# Something we can't encode. Let's preserve it as a string.
|
105
|
+
value.to_s.to_json
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/api_base.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "api_base/version"
|
2
|
+
require "api_base/base"
|
3
|
+
require "api_base/behaviours/shared"
|
4
|
+
require "api_base/behaviours/get_json"
|
5
|
+
require "api_base/behaviours/post_json"
|
6
|
+
require "api_base/models/api_log"
|
7
|
+
|
8
|
+
module ApiBase
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
# Your code goes here...
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api_base
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stefan Froelich
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-07-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: stoplight
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3'
|
55
|
+
description: Building blocks for building API Clients
|
56
|
+
email:
|
57
|
+
- sfroelich01@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- api_base.gemspec
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- db/migrate/20220612165032_create_api_logs.rb
|
73
|
+
- lib/api_base.rb
|
74
|
+
- lib/api_base/base.rb
|
75
|
+
- lib/api_base/behaviours/get_json.rb
|
76
|
+
- lib/api_base/behaviours/post_json.rb
|
77
|
+
- lib/api_base/behaviours/shared.rb
|
78
|
+
- lib/api_base/concerns/filterer.rb
|
79
|
+
- lib/api_base/concerns/traceable.rb
|
80
|
+
- lib/api_base/models/api_log.rb
|
81
|
+
- lib/api_base/version.rb
|
82
|
+
homepage: https://github.com/ussd-engine/api-base
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata:
|
86
|
+
allowed_push_host: https://rubygems.org
|
87
|
+
homepage_uri: https://github.com/ussd-engine/api-base
|
88
|
+
source_code_uri: https://github.com/ussd-engine/api-base
|
89
|
+
changelog_uri: https://github.com/ussd-engine/api-base
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 2.3.0
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubygems_version: 3.1.2
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: Building blocks for building API Clients
|
109
|
+
test_files: []
|