xendit 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []