easypost 3.5.1 → 5.2.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 +4 -4
- data/.gitattributes +9 -0
- data/.github/CODEOWNERS +2 -0
- data/.github/ISSUE_TEMPLATE/bug_report.yml +81 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.github/workflows/ci.yml +54 -5
- data/.gitignore +27 -17
- data/.gitmodules +3 -0
- data/CHANGELOG.md +295 -119
- data/Gemfile +2 -0
- data/Makefile +70 -0
- data/README.md +184 -72
- data/Rakefile +2 -1
- data/UPGRADE_GUIDE.md +181 -0
- data/VERSION +1 -1
- data/bin/easypost-irb +5 -3
- data/easypost.gemspec +27 -20
- data/lib/easypost/client.rb +179 -0
- data/lib/easypost/connection.rb +64 -0
- data/lib/easypost/constants.rb +15 -0
- data/lib/easypost/errors/api/api_error.rb +108 -0
- data/lib/easypost/errors/api/bad_request_error.rb +6 -0
- data/lib/easypost/errors/api/connection_error.rb +6 -0
- data/lib/easypost/errors/api/external_api_error.rb +18 -0
- data/lib/easypost/errors/api/forbidden_error.rb +6 -0
- data/lib/easypost/errors/api/gateway_timeout_error.rb +6 -0
- data/lib/easypost/errors/api/internal_server_error.rb +6 -0
- data/lib/easypost/errors/api/invalid_request_error.rb +6 -0
- data/lib/easypost/errors/api/method_not_allowed_error.rb +6 -0
- data/lib/easypost/errors/api/not_found_error.rb +6 -0
- data/lib/easypost/errors/api/payment_error.rb +6 -0
- data/lib/easypost/errors/api/proxy_error.rb +6 -0
- data/lib/easypost/errors/api/rate_limit_error.rb +6 -0
- data/lib/easypost/errors/api/redirect_error.rb +6 -0
- data/lib/easypost/errors/api/retry_error.rb +6 -0
- data/lib/easypost/errors/api/service_unavailable_error.rb +6 -0
- data/lib/easypost/errors/api/ssl_error.rb +6 -0
- data/lib/easypost/errors/api/timeout_error.rb +6 -0
- data/lib/easypost/errors/api/unauthorized_error.rb +6 -0
- data/lib/easypost/errors/api/unknown_api_error.rb +6 -0
- data/lib/easypost/errors/easy_post_error.rb +7 -0
- data/lib/easypost/errors/end_of_pagination_error.rb +7 -0
- data/lib/easypost/errors/filtering_error.rb +4 -0
- data/lib/easypost/errors/invalid_object_error.rb +4 -0
- data/lib/easypost/errors/invalid_parameter_error.rb +11 -0
- data/lib/easypost/errors/missing_parameter_error.rb +9 -0
- data/lib/easypost/errors/signature_verification_error.rb +4 -0
- data/lib/easypost/errors.rb +32 -0
- data/lib/easypost/hooks/request_context.rb +16 -0
- data/lib/easypost/hooks/response_context.rb +23 -0
- data/lib/easypost/hooks.rb +34 -0
- data/lib/easypost/http_client.rb +117 -0
- data/lib/easypost/internal_utilities.rb +66 -0
- data/lib/easypost/models/address.rb +5 -0
- data/lib/easypost/models/api_key.rb +5 -0
- data/lib/easypost/models/base.rb +58 -0
- data/lib/easypost/models/batch.rb +5 -0
- data/lib/easypost/models/brand.rb +5 -0
- data/lib/easypost/models/carbon_offset.rb +5 -0
- data/lib/easypost/models/carrier_account.rb +5 -0
- data/lib/easypost/models/carrier_type.rb +5 -0
- data/lib/easypost/models/customs_info.rb +5 -0
- data/lib/easypost/models/customs_item.rb +5 -0
- data/lib/easypost/models/end_shipper.rb +5 -0
- data/lib/easypost/models/error.rb +21 -0
- data/lib/easypost/models/event.rb +5 -0
- data/lib/easypost/models/insurance.rb +6 -0
- data/lib/easypost/models/order.rb +9 -0
- data/lib/easypost/models/parcel.rb +5 -0
- data/lib/easypost/models/payload.rb +5 -0
- data/lib/easypost/models/payment_method.rb +5 -0
- data/lib/easypost/models/pickup.rb +9 -0
- data/lib/easypost/models/pickup_rate.rb +5 -0
- data/lib/easypost/models/postage_label.rb +5 -0
- data/lib/easypost/models/rate.rb +5 -0
- data/lib/easypost/models/referral.rb +5 -0
- data/lib/easypost/models/refund.rb +5 -0
- data/lib/easypost/models/report.rb +5 -0
- data/lib/easypost/models/scan_form.rb +6 -0
- data/lib/easypost/models/shipment.rb +10 -0
- data/lib/easypost/models/tax_identifier.rb +6 -0
- data/lib/easypost/models/tracker.rb +5 -0
- data/lib/easypost/models/user.rb +5 -0
- data/lib/easypost/models/webhook.rb +6 -0
- data/lib/easypost/models.rb +36 -0
- data/lib/easypost/services/address.rb +50 -0
- data/lib/easypost/services/api_key.rb +8 -0
- data/lib/easypost/services/base.rb +27 -0
- data/lib/easypost/services/batch.rb +53 -0
- data/lib/easypost/services/beta_rate.rb +12 -0
- data/lib/easypost/services/beta_referral_customer.rb +40 -0
- data/lib/easypost/services/billing.rb +75 -0
- data/lib/easypost/services/carrier_account.rb +44 -0
- data/lib/easypost/services/carrier_metadata.rb +22 -0
- data/lib/easypost/services/carrier_type.rb +10 -0
- data/lib/easypost/services/customs_info.rb +17 -0
- data/lib/easypost/services/customs_item.rb +15 -0
- data/lib/easypost/services/end_shipper.rb +31 -0
- data/lib/easypost/services/event.rb +32 -0
- data/lib/easypost/services/insurance.rb +26 -0
- data/lib/easypost/services/order.rb +30 -0
- data/lib/easypost/services/parcel.rb +16 -0
- data/lib/easypost/services/pickup.rb +40 -0
- data/lib/easypost/services/rate.rb +8 -0
- data/lib/easypost/services/referral_customer.rb +103 -0
- data/lib/easypost/services/refund.rb +26 -0
- data/lib/easypost/services/report.rb +42 -0
- data/lib/easypost/services/scan_form.rb +25 -0
- data/lib/easypost/services/shipment.rb +106 -0
- data/lib/easypost/services/tracker.rb +38 -0
- data/lib/easypost/services/user.rb +66 -0
- data/lib/easypost/services/webhook.rb +34 -0
- data/lib/easypost/services.rb +33 -0
- data/lib/easypost/util.rb +160 -116
- data/lib/easypost/utilities/constants.rb +5 -0
- data/lib/easypost/utilities/json.rb +23 -0
- data/lib/easypost/utilities/static_mapper.rb +73 -0
- data/lib/easypost/utilities/system.rb +36 -0
- data/lib/easypost/version.rb +3 -1
- data/lib/easypost.rb +20 -143
- metadata +249 -46
- data/lib/easypost/address.rb +0 -58
- data/lib/easypost/api_key.rb +0 -2
- data/lib/easypost/batch.rb +0 -49
- data/lib/easypost/brand.rb +0 -9
- data/lib/easypost/carrier_account.rb +0 -5
- data/lib/easypost/carrier_type.rb +0 -2
- data/lib/easypost/customs_info.rb +0 -5
- data/lib/easypost/customs_item.rb +0 -5
- data/lib/easypost/error.rb +0 -31
- data/lib/easypost/event.rb +0 -7
- data/lib/easypost/insurance.rb +0 -2
- data/lib/easypost/object.rb +0 -151
- data/lib/easypost/order.rb +0 -28
- data/lib/easypost/parcel.rb +0 -2
- data/lib/easypost/pickup.rb +0 -26
- data/lib/easypost/pickup_rate.rb +0 -3
- data/lib/easypost/postage_label.rb +0 -2
- data/lib/easypost/print_job.rb +0 -2
- data/lib/easypost/printer.rb +0 -24
- data/lib/easypost/rate.rb +0 -2
- data/lib/easypost/refund.rb +0 -2
- data/lib/easypost/report.rb +0 -29
- data/lib/easypost/resource.rb +0 -75
- data/lib/easypost/scan_form.rb +0 -6
- data/lib/easypost/shipment.rb +0 -129
- data/lib/easypost/tax_identifier.rb +0 -2
- data/lib/easypost/tracker.rb +0 -7
- data/lib/easypost/user.rb +0 -56
- data/lib/easypost/webhook.rb +0 -29
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'services'
|
|
4
|
+
require_relative 'http_client'
|
|
5
|
+
require_relative 'internal_utilities'
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'securerandom'
|
|
8
|
+
|
|
9
|
+
class EasyPost::Client
|
|
10
|
+
attr_reader :open_timeout, :read_timeout, :api_base
|
|
11
|
+
|
|
12
|
+
# Initialize a new Client object
|
|
13
|
+
# @param api_key [String] the API key to be used for requests
|
|
14
|
+
# @param read_timeout [Integer] (60) the number of seconds to wait for a response before timing out
|
|
15
|
+
# @param open_timeout [Integer] (30) the number of seconds to wait for the connection to open before timing out
|
|
16
|
+
# @param api_base [String] ('https://api.easypost.com') the base URL for the API
|
|
17
|
+
# @param custom_client_exec [Proc] (nil) a custom client execution block to be used for requests instead of the default HTTP client (function signature: method, uri, headers, open_timeout, read_timeout, body = nil)
|
|
18
|
+
# @return [EasyPost::Client] the client object
|
|
19
|
+
def initialize(api_key:, read_timeout: 60, open_timeout: 30, api_base: 'https://api.easypost.com',
|
|
20
|
+
custom_client_exec: nil)
|
|
21
|
+
raise EasyPost::Errors::MissingParameterError.new('api_key') if api_key.nil?
|
|
22
|
+
|
|
23
|
+
@api_key = api_key
|
|
24
|
+
@api_base = api_base
|
|
25
|
+
@api_version = 'v2'
|
|
26
|
+
@read_timeout = read_timeout
|
|
27
|
+
@open_timeout = open_timeout
|
|
28
|
+
@lib_version = File.open(File.expand_path('../../VERSION', __dir__)).read.strip
|
|
29
|
+
|
|
30
|
+
# Make an HTTP client once, reuse it for all requests made by this client
|
|
31
|
+
# Configuration is immutable, so this is safe
|
|
32
|
+
@http_client = EasyPost::HttpClient.new(api_base, http_config, custom_client_exec)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
SERVICE_CLASSES = [
|
|
36
|
+
EasyPost::Services::Address,
|
|
37
|
+
EasyPost::Services::ApiKey,
|
|
38
|
+
EasyPost::Services::Batch,
|
|
39
|
+
EasyPost::Services::BetaRate,
|
|
40
|
+
EasyPost::Services::BetaReferralCustomer,
|
|
41
|
+
EasyPost::Services::Billing,
|
|
42
|
+
EasyPost::Services::CarrierAccount,
|
|
43
|
+
EasyPost::Services::CarrierMetadata,
|
|
44
|
+
EasyPost::Services::CarrierType,
|
|
45
|
+
EasyPost::Services::CustomsInfo,
|
|
46
|
+
EasyPost::Services::CustomsItem,
|
|
47
|
+
EasyPost::Services::EndShipper,
|
|
48
|
+
EasyPost::Services::Event,
|
|
49
|
+
EasyPost::Services::Insurance,
|
|
50
|
+
EasyPost::Services::Order,
|
|
51
|
+
EasyPost::Services::Parcel,
|
|
52
|
+
EasyPost::Services::Pickup,
|
|
53
|
+
EasyPost::Services::Rate,
|
|
54
|
+
EasyPost::Services::ReferralCustomer,
|
|
55
|
+
EasyPost::Services::Refund,
|
|
56
|
+
EasyPost::Services::Report,
|
|
57
|
+
EasyPost::Services::ScanForm,
|
|
58
|
+
EasyPost::Services::Shipment,
|
|
59
|
+
EasyPost::Services::Tracker,
|
|
60
|
+
EasyPost::Services::User,
|
|
61
|
+
EasyPost::Services::Webhook,
|
|
62
|
+
].freeze
|
|
63
|
+
|
|
64
|
+
# Loop over the SERVICE_CLASSES to automatically define the method and instance variable instead of manually define it
|
|
65
|
+
SERVICE_CLASSES.each do |cls|
|
|
66
|
+
define_method(EasyPost::InternalUtilities.to_snake_case(cls.name.split('::').last)) do
|
|
67
|
+
instance_variable_set("@#{EasyPost::InternalUtilities.to_snake_case(cls.name.split('::').last)}", cls.new(self))
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Make an HTTP request
|
|
72
|
+
#
|
|
73
|
+
# @param method [Symbol] the HTTP Verb (get, method, put, post, etc.)
|
|
74
|
+
# @param endpoint [String] URI path of the resource
|
|
75
|
+
# @param cls [Class] the class to deserialize to
|
|
76
|
+
# @param body [Object] (nil) object to be dumped to JSON
|
|
77
|
+
# @param api_version [String] the version of API to hit
|
|
78
|
+
# @raise [EasyPost::Error] if the response has a non-2xx status code
|
|
79
|
+
# @return [Hash] JSON object parsed from the response body
|
|
80
|
+
def make_request(
|
|
81
|
+
method,
|
|
82
|
+
endpoint,
|
|
83
|
+
cls = EasyPost::Models::EasyPostObject,
|
|
84
|
+
body = nil,
|
|
85
|
+
api_version = EasyPost::InternalUtilities::Constants::API_VERSION
|
|
86
|
+
)
|
|
87
|
+
response = @http_client.request(method, endpoint, nil, body, api_version)
|
|
88
|
+
|
|
89
|
+
potential_error = EasyPost::Errors::ApiError.handle_api_error(response)
|
|
90
|
+
raise potential_error unless potential_error.nil?
|
|
91
|
+
|
|
92
|
+
EasyPost::InternalUtilities::Json.convert_json_to_object(response.body, cls)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Subscribe a request hook
|
|
96
|
+
#
|
|
97
|
+
# @param name [Symbol] the name of the hook. Defaults ot a ranom hexadecimal-based symbol
|
|
98
|
+
# @param block [Block] a code block that will be executed before a request is made
|
|
99
|
+
# @return [Symbol] the name of the request hook
|
|
100
|
+
def subscribe_request_hook(name = SecureRandom.hex.to_sym, &block)
|
|
101
|
+
EasyPost::Hooks.subscribe(:request, name, block)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Unsubscribe a request hook
|
|
105
|
+
#
|
|
106
|
+
# @param name [Symbol] the name of the hook
|
|
107
|
+
# @return [Block] the hook code block
|
|
108
|
+
def unsubscribe_request_hook(name)
|
|
109
|
+
EasyPost::Hooks.unsubscribe(:request, name)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Unsubscribe all request hooks
|
|
113
|
+
#
|
|
114
|
+
# @return [Hash] a hash containing all request hook subscriptions
|
|
115
|
+
def unsubscribe_all_request_hooks
|
|
116
|
+
EasyPost::Hooks.unsubscribe_all(:request)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Subscribe a response hook
|
|
120
|
+
#
|
|
121
|
+
# @param name [Symbol] the name of the hook. Defaults ot a ranom hexadecimal-based symbol
|
|
122
|
+
# @param block [Block] a code block that will be executed upon receiving the response from a request
|
|
123
|
+
# @return [Symbol] the name of the response hook
|
|
124
|
+
def subscribe_response_hook(name = SecureRandom.hex.to_sym, &block)
|
|
125
|
+
EasyPost::Hooks.subscribe(:response, name, block)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Unsubscribe a response hook
|
|
129
|
+
#
|
|
130
|
+
# @param name [Symbol] the name of the hook
|
|
131
|
+
# @return [Block] the hook code block
|
|
132
|
+
def unsubscribe_response_hook(name)
|
|
133
|
+
EasyPost::Hooks.unsubscribe(:response, name)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Unsubscribe all response hooks
|
|
137
|
+
#
|
|
138
|
+
# @return [Hash] a hash containing all response hook subscriptions
|
|
139
|
+
def unsubscribe_all_response_hooks
|
|
140
|
+
EasyPost::Hooks.unsubscribe_all(:response)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def http_config
|
|
146
|
+
http_config = {
|
|
147
|
+
read_timeout: @read_timeout,
|
|
148
|
+
open_timeout: @open_timeout,
|
|
149
|
+
headers: default_headers,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
http_config[:min_version] = OpenSSL::SSL::TLS1_2_VERSION
|
|
153
|
+
http_config
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def default_headers
|
|
157
|
+
{
|
|
158
|
+
'Content-Type' => 'application/json',
|
|
159
|
+
'User-Agent' => user_agent,
|
|
160
|
+
'Authorization' => authorization,
|
|
161
|
+
}
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def user_agent
|
|
165
|
+
ruby_version = EasyPost::InternalUtilities::System.ruby_version
|
|
166
|
+
ruby_patchlevel = EasyPost::InternalUtilities::System.ruby_patchlevel
|
|
167
|
+
|
|
168
|
+
"EasyPost/#{@api_version} " \
|
|
169
|
+
"RubyClient/#{@lib_version} " \
|
|
170
|
+
"Ruby/#{ruby_version}-p#{ruby_patchlevel} " \
|
|
171
|
+
"OS/#{EasyPost::InternalUtilities::System.os_name} " \
|
|
172
|
+
"OSVersion/#{EasyPost::InternalUtilities::System.os_version} " \
|
|
173
|
+
"OSArch/#{EasyPost::InternalUtilities::System.os_arch}"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def authorization
|
|
177
|
+
"Bearer #{@api_key}"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
EasyPost::Connection = Struct.new(:uri, :config, keyword_init: true) do
|
|
4
|
+
# Make an HTTP request with Ruby's {Net::HTTP}
|
|
5
|
+
#
|
|
6
|
+
# @param method [Symbol] the HTTP Verb (get, method, put, post, etc.)
|
|
7
|
+
# @param path [String] URI path of the resource
|
|
8
|
+
# @param requested_api_key [String] ({EasyPost.api_key}) key set Authorization header.
|
|
9
|
+
# @param body [String] (nil) body of the request
|
|
10
|
+
# @raise [EasyPost::Error] if the response has a non-2xx status code
|
|
11
|
+
# @return [Hash] JSON object parsed from the response body
|
|
12
|
+
def call(method, path, api_key = nil, body = nil)
|
|
13
|
+
raise EasyPost::Errors::MissingParameterError.new('api_key') if api_key.nil?
|
|
14
|
+
|
|
15
|
+
connection =
|
|
16
|
+
if config[:proxy]
|
|
17
|
+
proxy_uri = URI(config[:proxy])
|
|
18
|
+
Net::HTTP.new(
|
|
19
|
+
uri.host,
|
|
20
|
+
uri.port,
|
|
21
|
+
proxy_uri.host,
|
|
22
|
+
proxy_uri.port,
|
|
23
|
+
proxy_uri.user,
|
|
24
|
+
proxy_uri.password,
|
|
25
|
+
)
|
|
26
|
+
else
|
|
27
|
+
Net::HTTP.new(uri.host, uri.port)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
connection.use_ssl = true
|
|
31
|
+
|
|
32
|
+
config.each do |name, value|
|
|
33
|
+
# Discrepancies between RestClient and Net::HTTP.
|
|
34
|
+
case name
|
|
35
|
+
when :verify_ssl
|
|
36
|
+
name = :verify_mode
|
|
37
|
+
when :timeout
|
|
38
|
+
name = :read_timeout
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Handled in the creation of the client.
|
|
42
|
+
if name == :proxy
|
|
43
|
+
next
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
connection.public_send("#{name}=", value)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
request = Net::HTTP.const_get(method.capitalize).new(path)
|
|
50
|
+
request.body = JSON.dump(EasyPost::InternalUtilities.objects_to_ids(body)) if body
|
|
51
|
+
|
|
52
|
+
EasyPost.default_headers.each_pair { |h, v| request[h] = v }
|
|
53
|
+
request['Authorization'] = EasyPost.authorization(api_key)
|
|
54
|
+
|
|
55
|
+
response = connection.request(request)
|
|
56
|
+
response_is_json = response['Content-Type'] ? response['Content-Type'].start_with?('application/json') : false
|
|
57
|
+
|
|
58
|
+
EasyPost.parse_response(
|
|
59
|
+
status: response.code.to_i,
|
|
60
|
+
body: response.body,
|
|
61
|
+
json: response_is_json,
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class EasyPost::Constants
|
|
4
|
+
API_ERROR_DETAILS_PARSING_ERROR = 'API error details could not be parsed.'
|
|
5
|
+
INVALID_PARAMETER = '%s is not a valid parameter.'
|
|
6
|
+
INVALID_PAYMENT_METHOD = 'The chosen payment method is not valid. Please try again.'
|
|
7
|
+
MISSING_REQUIRED_PARAMETER = 'Required parameter %s is missing.'
|
|
8
|
+
NO_MATCHING_RATES = 'No matching rates found.'
|
|
9
|
+
NO_MORE_PAGES = 'There are no more pages to retrieve.'
|
|
10
|
+
NO_PAYMENT_METHODS = 'Billing has not been setup for this user. Please add a payment method.'
|
|
11
|
+
STRIPE_CARD_CREATE_FAILED = 'Could not send card details to Stripe, please try again later.'
|
|
12
|
+
UNEXPECTED_HTTP_STATUS_CODE = 'Unexpected HTTP status code received: %s'
|
|
13
|
+
WEBHOOK_MISSING_SIGNATURE = 'Webhook received does not contain an HMAC signature.'
|
|
14
|
+
WEBHOOK_SIGNATURE_MISMATCH = 'Webhook received did not originate from EasyPost or had a webhook secret mismatch.'
|
|
15
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../easy_post_error'
|
|
4
|
+
require 'easypost/constants'
|
|
5
|
+
|
|
6
|
+
class EasyPost::Errors::ApiError < EasyPost::Errors::EasyPostError
|
|
7
|
+
attr_reader :status_code, :code, :errors
|
|
8
|
+
|
|
9
|
+
def initialize(message, status_code = nil, error_code = nil, sub_errors = nil)
|
|
10
|
+
super message
|
|
11
|
+
@status_code = status_code
|
|
12
|
+
@code = error_code
|
|
13
|
+
@errors = sub_errors
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def pretty_print
|
|
17
|
+
error_string = "#{code} (#{status_code}): #{message}"
|
|
18
|
+
errors&.each do |error|
|
|
19
|
+
error_string += "\nField: #{error.field}\nMessage: #{error.message}"
|
|
20
|
+
end
|
|
21
|
+
error_string
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Recursively traverses a JSON element to extract error messages and returns them as a comma-separated string.
|
|
25
|
+
def self.collect_error_messages(error_message, messages_list)
|
|
26
|
+
case error_message
|
|
27
|
+
when Hash
|
|
28
|
+
error_message.each_value { |value| collect_error_messages(value, messages_list) }
|
|
29
|
+
when Array
|
|
30
|
+
error_message.each { |value| collect_error_messages(value, messages_list) }
|
|
31
|
+
else
|
|
32
|
+
messages_list.push(error_message.to_s)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
messages_list.join(', ')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.handle_api_error(response)
|
|
39
|
+
status_code = response.code
|
|
40
|
+
status_code = status_code.to_i if status_code.is_a?(String)
|
|
41
|
+
|
|
42
|
+
if status_code >= 200 && status_code <= 299
|
|
43
|
+
return nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Try to parse the response body as JSON
|
|
47
|
+
begin
|
|
48
|
+
error_data = JSON.parse(response.body)['error']
|
|
49
|
+
|
|
50
|
+
error_message = error_data['message']
|
|
51
|
+
error_type = error_data['code']
|
|
52
|
+
errors = error_data['errors']&.map do |error|
|
|
53
|
+
EasyPost::Models::Error.from_api_error_response(error)
|
|
54
|
+
end
|
|
55
|
+
rescue StandardError
|
|
56
|
+
error_message = response.code.to_s
|
|
57
|
+
error_type = EasyPost::Constants::API_ERROR_DETAILS_PARSING_ERROR
|
|
58
|
+
errors = nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
cls = exception_cls_from_status_code(status_code)
|
|
62
|
+
|
|
63
|
+
if cls == EasyPost::Errors::UnknownApiError
|
|
64
|
+
return EasyPost::Errors::UnknownApiError.new(
|
|
65
|
+
EasyPost::Constants::UNEXPECTED_HTTP_STATUS_CODE % status_code,
|
|
66
|
+
status_code,
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Return (don't throw here) an instance of the appropriate error class
|
|
71
|
+
cls.new(error_message, status_code, error_type, errors)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.exception_cls_from_status_code(status_code)
|
|
75
|
+
case status_code
|
|
76
|
+
when 0
|
|
77
|
+
EasyPost::Errors::ConnectionError
|
|
78
|
+
when 300, 301, 302, 303, 304, 305, 306, 307, 308
|
|
79
|
+
EasyPost::Errors::RedirectError
|
|
80
|
+
when 400
|
|
81
|
+
EasyPost::Errors::BadRequestError
|
|
82
|
+
when 401
|
|
83
|
+
EasyPost::Errors::UnauthorizedError
|
|
84
|
+
when 402
|
|
85
|
+
EasyPost::Errors::PaymentError
|
|
86
|
+
when 403
|
|
87
|
+
EasyPost::Errors::ForbiddenError
|
|
88
|
+
when 404
|
|
89
|
+
EasyPost::Errors::NotFoundError
|
|
90
|
+
when 405
|
|
91
|
+
EasyPost::Errors::MethodNotAllowedError
|
|
92
|
+
when 408
|
|
93
|
+
EasyPost::Errors::TimeoutError
|
|
94
|
+
when 422
|
|
95
|
+
EasyPost::Errors::InvalidRequestError
|
|
96
|
+
when 429
|
|
97
|
+
EasyPost::Errors::RateLimitError
|
|
98
|
+
when 500
|
|
99
|
+
EasyPost::Errors::InternalServerError
|
|
100
|
+
when 502, 504
|
|
101
|
+
EasyPost::Errors::GatewayTimeoutError
|
|
102
|
+
when 503
|
|
103
|
+
EasyPost::Errors::ServiceUnavailableError
|
|
104
|
+
else
|
|
105
|
+
EasyPost::Errors::UnknownApiError
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class EasyPost::Errors::ExternalApiError < EasyPost::Errors::EasyPostError
|
|
4
|
+
attr_reader :status_code
|
|
5
|
+
|
|
6
|
+
def initialize(message, status_code = nil)
|
|
7
|
+
super message
|
|
8
|
+
@status_code = status_code
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def pretty_print
|
|
12
|
+
if status_code.nil?
|
|
13
|
+
return message
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
"(#{status_code}): #{message}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'easypost/constants'
|
|
4
|
+
|
|
5
|
+
class EasyPost::Errors::InvalidParameterError < EasyPost::Errors::EasyPostError
|
|
6
|
+
# @param [String] parameter The name of the parameter that was invalid.
|
|
7
|
+
# @param [String] suggestion Optional suggestion message for a valid parameter.
|
|
8
|
+
def initialize(parameter, suggestion = nil)
|
|
9
|
+
super EasyPost::Constants::INVALID_PARAMETER % parameter + (suggestion.nil? ? '' : " #{suggestion}")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EasyPost::Errors
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
require_relative 'errors/easy_post_error'
|
|
7
|
+
require_relative 'errors/end_of_pagination_error'
|
|
8
|
+
require_relative 'errors/api/external_api_error'
|
|
9
|
+
require_relative 'errors/filtering_error'
|
|
10
|
+
require_relative 'errors/invalid_object_error'
|
|
11
|
+
require_relative 'errors/invalid_parameter_error'
|
|
12
|
+
require_relative 'errors/missing_parameter_error'
|
|
13
|
+
require_relative 'errors/signature_verification_error'
|
|
14
|
+
require_relative 'errors/api/api_error'
|
|
15
|
+
require_relative 'errors/api/bad_request_error'
|
|
16
|
+
require_relative 'errors/api/connection_error'
|
|
17
|
+
require_relative 'errors/api/forbidden_error'
|
|
18
|
+
require_relative 'errors/api/gateway_timeout_error'
|
|
19
|
+
require_relative 'errors/api/internal_server_error'
|
|
20
|
+
require_relative 'errors/api/invalid_request_error'
|
|
21
|
+
require_relative 'errors/api/method_not_allowed_error'
|
|
22
|
+
require_relative 'errors/api/not_found_error'
|
|
23
|
+
require_relative 'errors/api/payment_error'
|
|
24
|
+
require_relative 'errors/api/proxy_error'
|
|
25
|
+
require_relative 'errors/api/rate_limit_error'
|
|
26
|
+
require_relative 'errors/api/redirect_error'
|
|
27
|
+
require_relative 'errors/api/retry_error'
|
|
28
|
+
require_relative 'errors/api/service_unavailable_error'
|
|
29
|
+
require_relative 'errors/api/ssl_error'
|
|
30
|
+
require_relative 'errors/api/timeout_error'
|
|
31
|
+
require_relative 'errors/api/unauthorized_error'
|
|
32
|
+
require_relative 'errors/api/unknown_api_error'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class EasyPost::Hooks::RequestContext
|
|
4
|
+
attr_reader :method, :path, :headers, :request_body, :request_timestamp, :request_uuid
|
|
5
|
+
|
|
6
|
+
def initialize(method:, path:, headers:, request_body:, request_timestamp:, request_uuid:)
|
|
7
|
+
@method = method
|
|
8
|
+
@path = path
|
|
9
|
+
@headers = headers
|
|
10
|
+
@request_body = request_body
|
|
11
|
+
@request_timestamp = request_timestamp
|
|
12
|
+
@request_uuid = request_uuid
|
|
13
|
+
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class EasyPost::Hooks::ResponseContext
|
|
4
|
+
attr_reader :http_status, :method, :path, :headers, :response_body,
|
|
5
|
+
:request_timestamp, :response_timestamp, :request_uuid,
|
|
6
|
+
:client_response_object
|
|
7
|
+
|
|
8
|
+
def initialize(http_status:, method:, path:, headers:, response_body:,
|
|
9
|
+
request_timestamp:, response_timestamp:, request_uuid:,
|
|
10
|
+
client_response_object:)
|
|
11
|
+
@http_status = http_status
|
|
12
|
+
@method = method
|
|
13
|
+
@path = path
|
|
14
|
+
@headers = headers
|
|
15
|
+
@response_body = response_body
|
|
16
|
+
@request_timestamp = request_timestamp
|
|
17
|
+
@response_timestamp = response_timestamp
|
|
18
|
+
@request_uuid = request_uuid
|
|
19
|
+
@client_response_object = client_response_object
|
|
20
|
+
|
|
21
|
+
freeze
|
|
22
|
+
end
|
|
23
|
+
end
|