xendit 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a4d561fbdd8488893b6dd4bad088ef99e40a03d8be788327a12126f841bfddf1
4
+ data.tar.gz: a4b4d9bedcce2f8c209ae8dcdadec6a57c78f5c796e1ccf2b90f3a2b5a974dcd
5
+ SHA512:
6
+ metadata.gz: 58fa9480ae46274de938091a63abfd04b8ada9ed8d8de64ac3dce5b112037c95f28705ba300731dd2dd9a818b13ec485b28677b6bd3d520d99e0a3e8de46c49c
7
+ data.tar.gz: 0501c6195bd6eb188cd879b42936486702645798239ac230439e5dea19073dca00c702266a56b6803464037c8a5172364ad7010462a5a1c3048b032d40860e7b
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'http://rubygems.org'
4
+
5
+ gemspec
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Xendit API Ruby Library
2
+
3
+ This library is the abstraction of Xendit API for access from applications written with Ruby/Rails.
4
+
5
+ <!-- toc -->
6
+
7
+ - [API Documentation](#api-documentation)
8
+ - [Requirements](#requirements)
9
+ - [Installation](#installation)
10
+ - [Usage](#usage)
11
+ * [Invoice Service](#invoice-service)
12
+
13
+ <!-- tocstop -->
14
+
15
+ ## API Documentation
16
+
17
+ Please check [Xendit API Reference](https://xendit.github.io/apireference/).
18
+
19
+ ## Requirements
20
+ - Ruby 2.5+.
21
+
22
+ ## Installation
23
+ Add this line to your application’s Gemfile:
24
+ ```bash
25
+ gem 'xendit'
26
+ ```
27
+ And then execute:
28
+ ```bash
29
+ $ bundle
30
+ ```
31
+ Access the library in Ruby/Rails project:
32
+ ```ruby
33
+ require 'xendit'
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ First, start by setting up with your account's **secret key** obtained from your [Xendit Dashboard](https://dashboard.xendit.co/settings/developers#api-keys).
39
+ Once done, you are ready to use all services provided in this library.
40
+
41
+ ```ruby
42
+ require 'xendit'
43
+
44
+ # Provide api key
45
+ Xendit.api_key = 'xnd_...'
46
+ ```
47
+
48
+ ### Invoice Service
49
+
50
+ Refer to [Xendit API Reference](https://xendit.github.io/apireference/#invoices) for more info about methods' parameters
51
+
52
+ Create an invoice
53
+ ```ruby
54
+ # setup invoice details
55
+ invoice_params = {
56
+ external_id: 'demo_147580196270',
57
+ payer_email: 'sample_email@xendit.co',
58
+ description: 'Trip to Bali',
59
+ amount: 10_000_000
60
+ }
61
+ # create an invoice
62
+ created_invoice = Xendit::Invoice.create invoice_params
63
+ ```
64
+
65
+ Get an invoice
66
+ ```ruby
67
+ # get an invoice
68
+ invoice = Xendit::Invoice.get '5efda8a20425db620ec35f43'
69
+ ```
70
+
71
+ Get all invoices
72
+ ```ruby
73
+ # setup filters
74
+ filter_params = {
75
+ limit: 3
76
+ }
77
+ # get invoices
78
+ invoices = Xendit::Invoice.get_all filter_params
79
+ ```
80
+
81
+ Expire an invoice
82
+ ```ruby
83
+ # expire an invoice
84
+ expired_invoice = Xendit::Invoice.expire '5efda8a20425db620ec35f43'
85
+ ```
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+
6
+ task default: %i[test rubocop]
7
+
8
+ task :test do
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.rspec_opts = '--format documentation'
11
+ t.pattern = 'spec/**/*_spec.rb'
12
+ end
13
+ Rake::Task['spec'].execute
14
+ end
15
+
16
+ task :rubocop do
17
+ RuboCop::RakeTask.new(:rubocop) do |t|
18
+ t.options = ['--display-cop-names', '--auto-correct-all']
19
+ end
20
+ end
data/bin/xendit ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'xendit'
5
+
6
+ puts Xendit.api_key = ARGV[0]
7
+ puts Xendit.base_url
8
+
9
+ puts Xendit::Invoice.get ARGV[1]
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './xendit'
4
+
5
+ begin
6
+ # create invoice
7
+ invoice_params = {
8
+ external_id: 'demo_147580196270',
9
+ payer_email: 'sample_email@xendit.co',
10
+ description: 'Trip to Bali',
11
+ amount: 10_000_000
12
+ }
13
+ created_invoice = Xendit::Invoice.create invoice_params
14
+ puts "\nCreated Invoice::"
15
+ puts created_invoice
16
+
17
+ # get invoice
18
+ invoice = Xendit::Invoice.get created_invoice['id']
19
+ puts "\nInvoice::"
20
+ puts invoice
21
+
22
+ # expire invoice
23
+ expired_invoice = Xendit::Invoice.expire created_invoice['id']
24
+ puts "\nExpired Invoice::"
25
+ puts expired_invoice
26
+
27
+ # get all invoices
28
+ filter_params = {
29
+ limit: 2
30
+ }
31
+ invoices = Xendit::Invoice.get_all filter_params
32
+ puts "\nInvoices::"
33
+ puts invoices
34
+ rescue Xendit::APIError => e
35
+ puts e
36
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/xendit' # require 'xendit'
4
+
5
+ Xendit.api_key = 'your_api_key'
6
+
7
+ # environment variables
8
+ puts "\nXendit API Key"
9
+ puts Xendit.api_key
10
+
11
+ puts "\nXendit API URL"
12
+ puts Xendit.base_url # change url if needed
data/lib/xendit.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'xendit/resources'
4
+
5
+ XENDIT_BASE_URL = 'https://api.xendit.co/'
6
+
7
+ module Xendit
8
+ class << self
9
+ attr_accessor :api_key
10
+ attr_writer :base_url
11
+
12
+ def base_url
13
+ @base_url ||= XENDIT_BASE_URL
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ module Xendit
7
+ class ApiOperations
8
+ class << self
9
+ def get(url, params = nil)
10
+ conn = create_connection
11
+ conn.get url, params
12
+ end
13
+
14
+ def post(url, **params)
15
+ conn = create_connection
16
+ conn.post url, JSON.generate(params)
17
+ end
18
+
19
+ private
20
+
21
+ def create_connection
22
+ Faraday.new(
23
+ url: Xendit.base_url,
24
+ headers: {'Content-Type' => 'application/json'}
25
+ ) do |conn|
26
+ conn.basic_auth(Xendit.api_key, '')
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xendit
4
+ class APIError < StandardError
5
+ attr_reader :error_code, :error_message, :http_status
6
+
7
+ def initialize(error_code, error_message, http_status)
8
+ @error_code = error_code
9
+ @error_message = error_message
10
+ @http_status = http_status
11
+
12
+ super to_s
13
+ end
14
+
15
+ def to_s
16
+ status_string = @http_status.nil? ? '' : "(Status #{@http_status}) "
17
+ error_code_string = @error_code.nil? ? '' : "#{error_code} - "
18
+ "#{status_string}#{error_code_string}#{@error_message}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'resources/invoice'
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ require_relative '../api_operations'
7
+ require_relative '../response'
8
+
9
+ module Xendit
10
+ class Invoice
11
+ class << self
12
+ def get(invoice_id)
13
+ # validation
14
+ raise ArgumentError, 'invoice_id is required and should be a string' \
15
+ if invoice_id.nil? || !invoice_id.is_a?(String)
16
+
17
+ resp = Xendit::ApiOperations.get "v2/invoices/#{invoice_id}"
18
+ Xendit::Response.handle_error_response resp
19
+
20
+ JSON.parse resp.body
21
+ end
22
+
23
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
24
+ def create(invoice_params)
25
+ # validation
26
+ raise ArgumentError, 'invoice body payload is required' \
27
+ if invoice_params.nil? || invoice_params.empty?
28
+ raise ArgumentError, 'payer_email is required and should be a string' \
29
+ if invoice_params[:payer_email].nil? ||
30
+ !invoice_params[:payer_email].is_a?(String)
31
+ raise ArgumentError, 'external_id is required and should be a string' \
32
+ if invoice_params[:external_id].nil? ||
33
+ !invoice_params[:external_id].is_a?(String)
34
+ raise ArgumentError, 'description is required and should be a string' \
35
+ if invoice_params[:description].nil? ||
36
+ !invoice_params[:description].is_a?(String)
37
+ raise ArgumentError, 'amount is required and should be an integer or float' \
38
+ if invoice_params[:amount].nil? ||
39
+ (!invoice_params[:amount].is_a?(Integer) &&
40
+ !invoice_params[:amount].is_a?(Float))
41
+
42
+ resp = Xendit::ApiOperations.post('v2/invoices', **invoice_params)
43
+ Xendit::Response.handle_error_response resp
44
+
45
+ JSON.parse resp.body
46
+ end
47
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
48
+
49
+ def expire(invoice_id)
50
+ # validation
51
+ raise ArgumentError, 'invoice_id is required and should be a string' \
52
+ if invoice_id.nil? || !invoice_id.is_a?(String)
53
+
54
+ resp = Xendit::ApiOperations.post "invoices/#{invoice_id}/expire!"
55
+ Xendit::Response.handle_error_response resp
56
+
57
+ JSON.parse resp.body
58
+ end
59
+
60
+ def get_all(filter_params = nil)
61
+ resp = Xendit::ApiOperations.get('v2/invoices', filter_params)
62
+ Xendit::Response.handle_error_response resp
63
+
64
+ JSON.parse resp.body
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './errors'
4
+
5
+ module Xendit
6
+ class Response
7
+ class << self
8
+ # rubocop:disable Metrics/AbcSize
9
+ def handle_error_response(resp)
10
+ # validation
11
+ raise ArgumentError, 'response is required' \
12
+ if resp.nil?
13
+ raise ArgumentError, 'response is in invalid format' \
14
+ if resp.status.nil? || resp.body.nil?
15
+
16
+ return unless resp.status >= 400
17
+
18
+ begin
19
+ body = JSON.parse resp.body
20
+ raise Xendit::APIError.new(body['error_code'], body['message'], resp.status)
21
+ rescue JSON::ParserError
22
+ raise Xendit::APIError.new('INVALID_RESPONSE_BODY_FORMAT', 'Response body is not in JSON format', 422)
23
+ end
24
+ end
25
+ # rubocop:enable Metrics/AbcSize
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xendit
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file was generated by the `rspec --init` command. Conventionally, all
4
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
6
+ # this file to always be loaded, without a need to explicitly require it in any
7
+ # files.
8
+ #
9
+ # Given that it is always loaded, you are encouraged to keep this file as
10
+ # light-weight as possible. Requiring heavyweight dependencies from this file
11
+ # will add to the boot time of your test suite on EVERY test run, even for an
12
+ # individual file that may not need all of that loaded. Instead, consider making
13
+ # a separate helper file that requires the additional dependencies and performs
14
+ # the additional setup, and require it from the spec files that actually need
15
+ # it.
16
+ #
17
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
18
+ RSpec.configure do |config|
19
+ # rspec-expectations config goes here. You can use an alternate
20
+ # assertion/expectation library such as wrong or the stdlib/minitest
21
+ # assertions if you prefer.
22
+ config.expect_with :rspec do |expectations|
23
+ # This option will default to `true` in RSpec 4. It makes the `description`
24
+ # and `failure_message` of custom matchers include text for helper methods
25
+ # defined using `chain`, e.g.:
26
+ # be_bigger_than(2).and_smaller_than(4).description
27
+ # # => "be bigger than 2 and smaller than 4"
28
+ # ...rather than:
29
+ # # => "be bigger than 2"
30
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
31
+ expectations.on_potential_false_positives = :nothing
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
44
+ # have no way to turn it off -- the option exists only for backwards
45
+ # compatibility in RSpec 3). It causes shared context metadata to be
46
+ # inherited by the metadata hash of host groups and examples, rather than
47
+ # triggering implicit auto-inclusion in groups with matching metadata.
48
+ config.shared_context_metadata_behavior = :apply_to_host_groups
49
+
50
+ # The settings below are suggested to provide a good initial experience
51
+ # with RSpec, but feel free to customize to your heart's content.
52
+ # # This allows you to limit a spec run to individual examples or groups
53
+ # # you care about by tagging them with `:focus` metadata. When nothing
54
+ # # is tagged with `:focus`, all examples get run. RSpec also provides
55
+ # # aliases for `it`, `describe`, and `context` that include `:focus`
56
+ # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
57
+ # config.filter_run_when_matching :focus
58
+ #
59
+ # # Allows RSpec to persist some state between runs in order to support
60
+ # # the `--only-failures` and `--next-failure` CLI options. We recommend
61
+ # # you configure your source control system to ignore this file.
62
+ # config.example_status_persistence_file_path = "spec/examples.txt"
63
+ #
64
+ # # Limits the available syntax to the non-monkey patched syntax that is
65
+ # # recommended. For more details, see:
66
+ # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
67
+ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
68
+ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
69
+ # config.disable_monkey_patching!
70
+ #
71
+ # # This setting enables warnings. It's recommended, but in some cases may
72
+ # # be too noisy due to issues in dependencies.
73
+ # config.warnings = true
74
+ #
75
+ # # Many RSpec users commonly either run the entire suite or an individual
76
+ # # file, and it's useful to allow more verbose output when running an
77
+ # # individual spec file.
78
+ # if config.files_to_run.one?
79
+ # # Use the documentation formatter for detailed output,
80
+ # # unless a formatter has already been configured
81
+ # # (e.g. via a command-line flag).
82
+ # config.default_formatter = "doc"
83
+ # end
84
+ #
85
+ # # Print the 10 slowest examples and example groups at the
86
+ # # end of the spec run, to help surface which specs are running
87
+ # # particularly slow.
88
+ # config.profile_examples = 10
89
+ #
90
+ # # Run specs in random order to surface order dependencies. If you find an
91
+ # # order dependency and want to debug it, you can fix the order by providing
92
+ # # the seed, which is printed after each run.
93
+ # # --seed 1234
94
+ # config.order = :random
95
+ #
96
+ # # Seed global randomization in this process using the `--seed` CLI option.
97
+ # # Setting this allows you to use `--seed` to deterministically reproduce
98
+ # # test failures related to randomization by passing the same `--seed` value
99
+ # # as the one that triggered the failure.
100
+ # Kernel.srand config.seed
101
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xendit/api_operations'
4
+
5
+ describe Xendit::ApiOperations do
6
+ describe '.create_connection' do
7
+ it 'should returns a connection object' do
8
+ conn = described_class.send(:create_connection)
9
+ expect(conn).to be_an_instance_of(Faraday::Connection)
10
+ end
11
+ end
12
+
13
+ describe '.get' do
14
+ context 'given a GET one request' do
15
+ let(:url) { 'invoices/1273018302173' }
16
+ let(:response) do
17
+ OpenStruct.new({
18
+ status: 200,
19
+ body: '{"id":"1273018302173","status":"PENDING"}'
20
+ })
21
+ end
22
+
23
+ it 'should return the object' do
24
+ allow_any_instance_of(Faraday::Connection).to receive(:get).with(url, nil).and_return(response)
25
+
26
+ result = described_class.get url
27
+ expect(result).to eq(response)
28
+ end
29
+ end
30
+
31
+ context 'given a GET all request' do
32
+ let(:url) { 'invoices' }
33
+ let(:filter_params) do
34
+ {
35
+ limit: 2
36
+ }
37
+ end
38
+ let(:response) do
39
+ OpenStruct.new({
40
+ status: 200,
41
+ body: '[{"id":"1273018302173","status":"PENDING"},{"id":"1273018302174","status":"PENDING"}]'
42
+ })
43
+ end
44
+
45
+ it 'should return objects based on filtered requirements' do
46
+ allow_any_instance_of(Faraday::Connection).to receive(:get).with(url, filter_params).and_return(response)
47
+
48
+ result = described_class.get url, filter_params
49
+ expect(result).to eq(response)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '.post' do
55
+ context 'given a POST request' do
56
+ let(:url) { 'invoices' }
57
+ let(:post_params) do
58
+ {
59
+ status: 'PENDING'
60
+ }
61
+ end
62
+ let(:response) do
63
+ OpenStruct.new({
64
+ status: 200,
65
+ body: '{"id":"1273018302173","status":"PENDING"'
66
+ })
67
+ end
68
+
69
+ it 'should return the created object' do
70
+ allow_any_instance_of(Faraday::Connection).to receive(:post).with(url, JSON.generate(post_params)).and_return(response)
71
+
72
+ result = described_class.post url, **post_params
73
+ expect(result).to eq(response)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xendit/resources/invoice'
4
+
5
+ describe Xendit::Invoice do
6
+ let(:invoice) do
7
+ {
8
+ 'id' => '1273018302173',
9
+ 'external_id' => 'demo_147580196270',
10
+ 'user_id' => '12234238302171',
11
+ 'status' => 'PENDING',
12
+ 'merchant_name' => 'COMPANY ABC',
13
+ 'merchant_profile_picture_url' => 'dummy.png',
14
+ 'amount' => 10_000_000,
15
+ 'payer_email' => 'sample_email@xendit.co',
16
+ 'description' => 'Trip to Bali',
17
+ 'expiry_date' => '2021-02-13T17:53:06.980Z',
18
+ 'invoice_url' => 'https://checkout.xendit.co/web/1273018302173',
19
+ 'created' => '2021-02-09T17:53:07.102Z',
20
+ 'updated' => '2021-02-09T17:53:07.102Z',
21
+ 'currency' => 'IDR'
22
+ }
23
+ end
24
+
25
+ describe '.create' do
26
+ context 'given a complete invoice details' do
27
+ let(:url) { 'v2/invoices' }
28
+ let(:invoice_params) do
29
+ {
30
+ external_id: 'demo_147580196270',
31
+ payer_email: 'sample_email@xendit.co',
32
+ description: 'Trip to Bali',
33
+ amount: 10_000_000
34
+ }
35
+ end
36
+ let(:api_operation_response) do
37
+ OpenStruct.new({
38
+ status: 200,
39
+ body: JSON.generate(invoice)
40
+ })
41
+ end
42
+
43
+ it 'should return the created invoice object' do
44
+ allow(Xendit::ApiOperations).to receive(:post).with(url, invoice_params).and_return(api_operation_response)
45
+
46
+ result = described_class.create invoice_params
47
+ expect(result).to eq(invoice)
48
+ end
49
+ end
50
+
51
+ context 'given an incomplete invoice details' do
52
+ let(:invalid_invoice_params) do
53
+ {
54
+ external_id: 'demo_147580196270',
55
+ payer_email: 'sample_email@xendit.co'
56
+ }
57
+ end
58
+
59
+ it 'should raise argument error' do
60
+ expect(-> { described_class.create invalid_invoice_params }).
61
+ to raise_error(ArgumentError)
62
+ end
63
+ end
64
+ end
65
+
66
+ describe '.get' do
67
+ let(:url) { "v2/invoices/#{invoice['id']}" }
68
+ let(:api_operation_response) do
69
+ OpenStruct.new({
70
+ status: 200,
71
+ body: JSON.generate(invoice)
72
+ })
73
+ end
74
+
75
+ it 'should return a invoice object' do
76
+ allow(Xendit::ApiOperations).to receive(:get).with(url).and_return(api_operation_response)
77
+
78
+ result = described_class.get invoice['id']
79
+ expect(result).to eq(invoice)
80
+ end
81
+ end
82
+
83
+ describe '.get_all' do
84
+ let(:url) { 'v2/invoices' }
85
+ let(:api_operation_response) do
86
+ OpenStruct.new({
87
+ status: 200,
88
+ body: JSON.generate(invoice)
89
+ })
90
+ end
91
+
92
+ it 'should return invoice object(s)' do
93
+ allow(Xendit::ApiOperations).to receive(:get).with(url, nil).and_return(api_operation_response)
94
+
95
+ result = described_class.get_all
96
+ expect(result).to eq(invoice)
97
+ end
98
+ end
99
+
100
+ describe '.expire!' do
101
+ let(:url) { "invoices/#{invoice['id']}/expire!" }
102
+ let(:expired_invoice) { invoice.clone.merge('status' => 'EXPIRED') }
103
+ let(:api_operation_response) do
104
+ OpenStruct.new({
105
+ status: 200,
106
+ body: JSON.generate(expired_invoice)
107
+ })
108
+ end
109
+
110
+ it 'should return the expired invoice object' do
111
+ allow(Xendit::ApiOperations).to receive(:post).with(url).and_return(api_operation_response)
112
+
113
+ result = described_class.expire invoice['id']
114
+ expect(result).to eq(expired_invoice)
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xendit/response'
4
+
5
+ describe Xendit::Response do
6
+ describe '.create_connection' do
7
+ context 'given no response' do
8
+ it 'should raise argument error' do
9
+ expect(-> { described_class.handle_error_response }).
10
+ to raise_error(ArgumentError)
11
+ end
12
+ end
13
+
14
+ context 'given an invalid response' do
15
+ let(:invalid_response) do
16
+ OpenStruct.new({
17
+ invalid_status: 200,
18
+ invalid_body: '{"id":"1273018302173","status":"PENDING"}'
19
+ })
20
+ end
21
+
22
+ it 'should raise argument error' do
23
+ expect(-> { described_class.handle_error_response(invalid_response) }).
24
+ to raise_error(ArgumentError)
25
+ end
26
+ end
27
+
28
+ context 'given an invalid body response' do
29
+ let(:invalid_body_response) do
30
+ OpenStruct.new({
31
+ status: 400,
32
+ body: 'this is not a json'
33
+ })
34
+ end
35
+
36
+ it 'should raise API error' do
37
+ expect(-> { described_class.handle_error_response(invalid_body_response) }).
38
+ to raise_error(Xendit::APIError)
39
+ end
40
+ end
41
+
42
+ context 'given an error response' do
43
+ let(:error_response) do
44
+ OpenStruct.new({
45
+ status: 400,
46
+ body: '{"error_code":"INVALID_API_KEY","message":"API key is not authorized for this API service"}'
47
+ })
48
+ end
49
+
50
+ it 'should raise API error' do
51
+ expect(-> { described_class.handle_error_response(error_response) }).
52
+ to raise_error(Xendit::APIError)
53
+ end
54
+ end
55
+
56
+ context 'given a valid response' do
57
+ let(:valid_response) do
58
+ OpenStruct.new({
59
+ status: 200,
60
+ body: '{"id":"1273018302173","status":"PENDING"}'
61
+ })
62
+ end
63
+
64
+ it 'should not raise API error' do
65
+ expect(-> { described_class.handle_error_response(valid_response) }).
66
+ not_to raise_error(Xendit::APIError)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xendit'
4
+
5
+ describe Xendit do
6
+ describe 'API key' do
7
+ let(:api_key) { 'this_is_my_api_key' }
8
+
9
+ context 'given no API URL provided' do
10
+ it 'should return nil' do
11
+ expect(described_class.api_key).to be_nil
12
+ end
13
+ end
14
+
15
+ context 'given an API key provided' do
16
+ it 'should return the given API key' do
17
+ described_class.api_key = api_key
18
+ expect(Xendit.api_key).to eq(api_key)
19
+ end
20
+ end
21
+ end
22
+
23
+ describe 'API base URL' do
24
+ let(:default_base_url) { 'https://api.xendit.co/' }
25
+ let(:base_url) { 'https://api.xendit.staging.co/' }
26
+
27
+ context 'given no API URL provided' do
28
+ it 'should return the default base_url' do
29
+ expect(described_class.base_url).to eq(default_base_url)
30
+ end
31
+ end
32
+
33
+ context 'given an API URL' do
34
+ it 'should return the given base_url' do
35
+ Xendit.base_url = base_url
36
+ expect(described_class.base_url).to eq(base_url)
37
+ end
38
+ end
39
+ end
40
+ end
data/xendit.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/xendit/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'xendit'
7
+ spec.version = Xendit::VERSION
8
+
9
+ spec.summary = 'Xendit Ruby API client library'
10
+
11
+ spec.authors = ['@yongquanben']
12
+ spec.email = 'benjamin@xendit.co'
13
+ spec.homepage = 'https://github.com/xendit/xendit-ruby'
14
+ spec.licenses = ['MIT']
15
+
16
+ spec.required_ruby_version = '>= 2.5'
17
+
18
+ spec.files = Dir['README.md', '{examples,lib,spec}/**/*.rb',
19
+ 'xendit.gemspec',
20
+ 'Gemfile', 'Rakefile']
21
+
22
+ spec.executables << 'xendit'
23
+
24
+ spec.add_dependency 'faraday', '~> 1.3'
25
+
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
+
28
+ spec.add_development_dependency 'rubocop', '~> 1.9'
29
+ spec.add_development_dependency 'rubocop-performance', '~> 1.9'
30
+
31
+ spec.add_development_dependency 'rspec', '~> 3.6'
32
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xendit
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - "@yongquanben"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-performance
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.6'
83
+ description:
84
+ email: benjamin@xendit.co
85
+ executables:
86
+ - xendit
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - Gemfile
91
+ - README.md
92
+ - Rakefile
93
+ - bin/xendit
94
+ - examples/invoice.rb
95
+ - examples/xendit.rb
96
+ - lib/xendit.rb
97
+ - lib/xendit/api_operations.rb
98
+ - lib/xendit/errors.rb
99
+ - lib/xendit/resources.rb
100
+ - lib/xendit/resources/invoice.rb
101
+ - lib/xendit/response.rb
102
+ - lib/xendit/version.rb
103
+ - spec/spec_helper.rb
104
+ - spec/xendit/api_operations_spec.rb
105
+ - spec/xendit/resources/invoice_spec.rb
106
+ - spec/xendit/response_spec.rb
107
+ - spec/xendit_spec.rb
108
+ - xendit.gemspec
109
+ homepage: https://github.com/xendit/xendit-ruby
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: '2.5'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.1.2
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Xendit Ruby API client library
132
+ test_files: []