postmen 1.0.0.pre.alpha.1 → 1.0.0.pre.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/postmen/connection.rb +82 -8
- data/lib/postmen/errors.rb +52 -0
- data/lib/postmen/response.rb +12 -0
- data/lib/postmen/shipper_account.rb +42 -4
- data/lib/postmen/shipper_account_collection.rb +6 -1
- data/lib/postmen/version.rb +1 -1
- data/lib/postmen.rb +15 -12
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05652c1c08402bef17419ea6b02586580eae907e
|
4
|
+
data.tar.gz: 8f6676faa166b9ba2f59248593198cfc4d60e8c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47156b956f5511b485afbee474f381f78e080d7844d642e7d39654417039cfc5b7bea409adef20ffc65df77d8d5bc1bcc5f31f1b04ab8f0b7d9230e30abdf9a0
|
7
|
+
data.tar.gz: bf6f08c3f8ace491be96fe8d75b90a82663386008a64ecb6ddd633ea7a1dcb5f3aa4ad9061e4dab3e3a91162cf8acc9bb37c548e7bc84127283133c3ee778ec8
|
data/lib/postmen/connection.rb
CHANGED
@@ -5,6 +5,12 @@ class Postmen
|
|
5
5
|
# Maximum number of retries
|
6
6
|
MAX_REQUESTS = 5
|
7
7
|
|
8
|
+
# Main domain used during normal usage.
|
9
|
+
MAIN_DOMAIN = 'postmen.com'.freeze
|
10
|
+
|
11
|
+
# Failover domain used during DNS issues with main domain
|
12
|
+
FAILOVER_DOMAIN = 'postmen.net'.freeze
|
13
|
+
|
8
14
|
def initialize
|
9
15
|
@requests = 0
|
10
16
|
end
|
@@ -17,12 +23,9 @@ class Postmen
|
|
17
23
|
# .get('/labels')
|
18
24
|
# .get('/labels', { params: { limit: 5 } })
|
19
25
|
def get(path, options = {})
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
raise if @requests > MAX_REQUESTS
|
24
|
-
sleep(60)
|
25
|
-
retry
|
26
|
+
with_error_handling do
|
27
|
+
Response.new(raw_get(path, options)).tap(&:parse_response!)
|
28
|
+
end
|
26
29
|
end
|
27
30
|
|
28
31
|
# Performs a HTTP POST request.
|
@@ -33,7 +36,9 @@ class Postmen
|
|
33
36
|
# .post('/labels')
|
34
37
|
# .post('/labels', { json: { my: { sample: :data } } })
|
35
38
|
def post(path, options = {})
|
36
|
-
|
39
|
+
with_error_handling do
|
40
|
+
Response.new(raw_post(path, options))
|
41
|
+
end
|
37
42
|
end
|
38
43
|
|
39
44
|
# Performs a HTTP PUT request.
|
@@ -44,8 +49,11 @@ class Postmen
|
|
44
49
|
# .put('/shipper-accounts/123/info')
|
45
50
|
# ..put('/shipper-accounts/123/info', { json: { my: { sample: :data } } })
|
46
51
|
def put(path, options = {})
|
47
|
-
|
52
|
+
with_error_handling do
|
53
|
+
Response.new(raw_put(path, options)).tap(&:parse_response!)
|
54
|
+
end
|
48
55
|
end
|
56
|
+
|
49
57
|
# Performs a HTTP DELETE request
|
50
58
|
#
|
51
59
|
# @param path [String]
|
@@ -57,8 +65,74 @@ class Postmen
|
|
57
65
|
.delete(get_full_url(path))
|
58
66
|
end
|
59
67
|
|
68
|
+
# Returns the endpoint used in SDK, based on the region(subdomain) and
|
69
|
+
# a failover switch
|
70
|
+
#
|
71
|
+
# @param subdomain [String] The region/subdomain used.
|
72
|
+
# @param failover [Boolean]
|
73
|
+
def self.endpoint(subdomain, failover = false)
|
74
|
+
URI::HTTPS.build(scheme: 'https',
|
75
|
+
host: hostname(subdomain, failover),
|
76
|
+
path: '/v3').to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the hostname based on the region(subdomain) and a failover switch
|
80
|
+
#
|
81
|
+
# @param subdomain [String] The region/subdomain used.
|
82
|
+
# @param failover [Boolean]
|
83
|
+
def self.hostname(subdomain, failover)
|
84
|
+
base = failover ? FAILOVER_DOMAIN : MAIN_DOMAIN
|
85
|
+
[subdomain, base].join('.')
|
86
|
+
end
|
87
|
+
|
60
88
|
private
|
61
89
|
|
90
|
+
# rubocop:disable Metrics/MethodLength
|
91
|
+
# rubocop:disable Metrics/AbcSize
|
92
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
93
|
+
def with_error_handling
|
94
|
+
raise ArgumentError unless block_given?
|
95
|
+
|
96
|
+
begin
|
97
|
+
yield
|
98
|
+
# Rescue from any connection issues
|
99
|
+
rescue HTTP::ConnectionError
|
100
|
+
# Raise error if we already tried to use failover domain
|
101
|
+
raise if Postmen.failover?
|
102
|
+
# Switch to failover domain & retry the request
|
103
|
+
Postmen.failover!
|
104
|
+
retry
|
105
|
+
# Handle Rate limits.
|
106
|
+
# Rate limits are being reset every 60 seconds - we're retrying
|
107
|
+
# given request after that.
|
108
|
+
# @see https://docs.postmen.com/ratelimit.html Documentation
|
109
|
+
rescue RateLimitExceeded
|
110
|
+
@requests += 1
|
111
|
+
raise if @requests > MAX_REQUESTS
|
112
|
+
sleep(60)
|
113
|
+
retry
|
114
|
+
# If the resource was not found, simply re-raise the exception
|
115
|
+
rescue ResourceNotFound
|
116
|
+
raise
|
117
|
+
# Handle request errors.
|
118
|
+
# Our current error handling policy depends on the error type.
|
119
|
+
# If the API returns information, that the request is retriable,
|
120
|
+
# We're waiting 5 seconds, and trying again with exact same request.
|
121
|
+
# To prevent having infinite loops, we're trying maximum 5 times.
|
122
|
+
# In case that we were unable to make successfull request with that 5 tries,
|
123
|
+
# MaximumNumberOfRetriesReachedError is being raised.
|
124
|
+
#
|
125
|
+
# @raise RequestError if the request is not retriable
|
126
|
+
# @raise MaximumNumberOfRetriesReachedError if the API returned error after 5 retries
|
127
|
+
rescue RequestError => error
|
128
|
+
raise unless error.retriable?
|
129
|
+
raise MaximumNumberOfRetriesReachedError, self if @requests > MAX_REQUESTS
|
130
|
+
@requests += 1
|
131
|
+
sleep(5)
|
132
|
+
retry
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
62
136
|
def raw_get(path, options)
|
63
137
|
HTTP
|
64
138
|
.headers(headers)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Postmen
|
2
|
+
# Generic Exception class, all other exceptions should inherit from this class
|
3
|
+
Error = Class.new(StandardError)
|
4
|
+
|
5
|
+
# Generic exception raised if the API returns an error
|
6
|
+
class RequestError < Error
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@request, :meta, :data
|
10
|
+
|
11
|
+
def initialize(request)
|
12
|
+
@request = request
|
13
|
+
end
|
14
|
+
|
15
|
+
# Indicates whether request is retryable.
|
16
|
+
# @see https://docs.postmen.com/errors.html API Documentation
|
17
|
+
def retryable?
|
18
|
+
meta.fetch(:retryable, false)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns details for the request error
|
22
|
+
# @see https://docs.postmen.com/#meta API Documentation
|
23
|
+
def details
|
24
|
+
meta[:details]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Internal API error code
|
28
|
+
# @see https://docs.postmen.com/errors.html List of Error codes
|
29
|
+
def code
|
30
|
+
meta[:code]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns human-readable error message
|
34
|
+
# @see https://docs.postmen.com/#meta API Documentation
|
35
|
+
def message
|
36
|
+
meta[:message]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :request
|
42
|
+
end
|
43
|
+
|
44
|
+
# Exception raised if rate limit was exceeded
|
45
|
+
RateLimitExceeded = Class.new(Error)
|
46
|
+
# Exception raised in case of any connection error
|
47
|
+
ConnectionError = Class.new(Error)
|
48
|
+
# Exception raised if retriable request reached maximum number of attempts.
|
49
|
+
MaximumNumberOfRetriesReachedError = Class.new(Error)
|
50
|
+
# Expcetion raised if resource was not found.
|
51
|
+
ResourceNotFound = Class.new(RequestError)
|
52
|
+
end
|
data/lib/postmen/response.rb
CHANGED
@@ -16,12 +16,24 @@ class Postmen
|
|
16
16
|
@meta ||= parsed_response[:meta]
|
17
17
|
end
|
18
18
|
|
19
|
+
# Holds the data
|
20
|
+
# @see https://docs.postmen.com/#data API Documentation
|
21
|
+
# @return [Hash]
|
22
|
+
def data
|
23
|
+
@data ||= parsed_response[:data]
|
24
|
+
end
|
25
|
+
|
19
26
|
# Parses the json response
|
20
27
|
# @return [Hash]
|
21
28
|
def parsed_response
|
22
29
|
@parsed_response ||= JSON.parse(body, symbolize_names: true)
|
23
30
|
end
|
24
31
|
|
32
|
+
# Checks if response were successfull
|
33
|
+
def success?
|
34
|
+
meta[:code] == 200
|
35
|
+
end
|
36
|
+
|
25
37
|
# Checks if rate limit was exceeded
|
26
38
|
def rate_limit_exceeded?
|
27
39
|
code == 429
|
@@ -47,11 +47,46 @@ class Postmen
|
|
47
47
|
#
|
48
48
|
# @see https://docs.postmen.com/api.html#shipper-accounts-update-a-shipper-account-credentials
|
49
49
|
# @return [ShipperAccount] Updated ShipperAccount resource
|
50
|
-
|
51
|
-
|
50
|
+
# @raise [RequestError]
|
51
|
+
def update_credentials!(params = {})
|
52
|
+
response = Connection.new.put(
|
52
53
|
"/shipper-accounts/#{@id}/credentials",
|
53
|
-
ShipperAccountUpdateCredentialsQuery.new(params).
|
54
|
+
ShipperAccountUpdateCredentialsQuery.new(params).to_query
|
55
|
+
)
|
56
|
+
|
57
|
+
raise RequestError, response unless response.success?
|
58
|
+
|
59
|
+
ShipperAccount.new(response.data)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Update a ShipperAccount credentials
|
63
|
+
#
|
64
|
+
# @see https://docs.postmen.com/api.html#shipper-accounts-update-a-shipper-account-credentials
|
65
|
+
# @return [ShipperAccount] Updated ShipperAccount resource
|
66
|
+
# @return [Hash] a Hash with detailed information about what went wrong
|
67
|
+
def update_credentials(params = {})
|
68
|
+
update_credentials!(params)
|
69
|
+
rescue RequestError => error
|
70
|
+
error.meta
|
71
|
+
end
|
72
|
+
|
73
|
+
# Update a shipper account information
|
74
|
+
#
|
75
|
+
# @see https://docs.postmen.com/api.html#shipper-accounts-update-a-shipper-account-information API Documentation
|
76
|
+
# @example
|
77
|
+
# .update(description: "Your new description")
|
78
|
+
# .update(address: {})
|
79
|
+
# @return [ShipperAccount] Updated ShipperAccount resource
|
80
|
+
# @raise [RequestError]
|
81
|
+
def update!(params = {})
|
82
|
+
response = Connection.new.put(
|
83
|
+
"/shipper-accounts/#{@id}/info",
|
84
|
+
ShipperAccountUpdateQuery.new(params.merge(subject: self)).to_query
|
54
85
|
)
|
86
|
+
|
87
|
+
raise RequestError, response unless response.success?
|
88
|
+
|
89
|
+
ShipperAccount.new(response.data)
|
55
90
|
end
|
56
91
|
|
57
92
|
# Update a shipper account information
|
@@ -61,8 +96,11 @@ class Postmen
|
|
61
96
|
# .update(description: "Your new description")
|
62
97
|
# .update(address: {})
|
63
98
|
# @return [ShipperAccount] Updated ShipperAccount resource
|
99
|
+
# @return [Hash] a Hash with detailed information about what went wrong
|
64
100
|
def update(params = {})
|
65
|
-
|
101
|
+
update!(params)
|
102
|
+
rescue RequestError => error
|
103
|
+
error.meta
|
66
104
|
end
|
67
105
|
end
|
68
106
|
end
|
@@ -33,7 +33,12 @@ class Postmen
|
|
33
33
|
# @see https://docs.postmen.com/api.html#shipper-accounts-create-a-shipper-account API documentation
|
34
34
|
# @return [ShipperAccount]
|
35
35
|
def self.create(params)
|
36
|
-
ShipperAccount.new(
|
36
|
+
ShipperAccount.new(
|
37
|
+
Connection.new.post(
|
38
|
+
'/shipper-accounts',
|
39
|
+
CreateShipperAccountQuery.new(params).to_query
|
40
|
+
).parsed_response[:data]
|
41
|
+
)
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
data/lib/postmen/version.rb
CHANGED
data/lib/postmen.rb
CHANGED
@@ -6,6 +6,7 @@ require 'pathname'
|
|
6
6
|
require 'forwardable'
|
7
7
|
|
8
8
|
require 'postmen/version'
|
9
|
+
require 'postmen/errors'
|
9
10
|
require 'postmen/types'
|
10
11
|
require 'postmen/connection'
|
11
12
|
require 'postmen/collection_proxy'
|
@@ -37,17 +38,6 @@ require 'postmen/manifest_collection'
|
|
37
38
|
class Postmen
|
38
39
|
extend Dry::Configurable
|
39
40
|
|
40
|
-
# Generic Exception class, all other exceptions should inherit from this class
|
41
|
-
Error = Class.new(StandardError)
|
42
|
-
# Exception raised if rate limit was exceeded
|
43
|
-
RateLimitExceeded = Class.new(Error)
|
44
|
-
# Exception raised in case of any connection error
|
45
|
-
ConnectionError = Class.new(Error)
|
46
|
-
# Generic exception raised if the API returns an error
|
47
|
-
RequestError = Class.new(Error)
|
48
|
-
# Expcetion raised if resource was not found.
|
49
|
-
ResourceNotFound = Class.new(RequestError)
|
50
|
-
|
51
41
|
# @#!attribute [rw] api_key [String] API key taken from the application.
|
52
42
|
setting :api_key
|
53
43
|
|
@@ -57,11 +47,14 @@ class Postmen
|
|
57
47
|
# @#!attribute endpoint [String] Endoint name - specify if you'd like to use custom endpoint
|
58
48
|
setting :endpoint
|
59
49
|
|
50
|
+
# @#!attribute failover [Bool] Indicates if the SDK is using failover domain.
|
51
|
+
setting :failover, false
|
52
|
+
|
60
53
|
# Returns the endpoint used in all queries
|
61
54
|
#
|
62
55
|
# @return [String] endpoint url
|
63
56
|
def self.endpoint
|
64
|
-
config.endpoint || "
|
57
|
+
config.endpoint || Connection.endpoint("#{config.region}-api", config.failover)
|
65
58
|
end
|
66
59
|
|
67
60
|
# Returns path where gem is installed
|
@@ -70,4 +63,14 @@ class Postmen
|
|
70
63
|
def self.root
|
71
64
|
Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), '../')))
|
72
65
|
end
|
66
|
+
|
67
|
+
# Checks wheter we're in failover mode
|
68
|
+
def self.failover?
|
69
|
+
!!config.failover
|
70
|
+
end
|
71
|
+
|
72
|
+
# Switch to failover domain
|
73
|
+
def self.failover!
|
74
|
+
config.failover = true
|
75
|
+
end
|
73
76
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: postmen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.alpha.
|
4
|
+
version: 1.0.0.pre.alpha.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- postmen.com
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- lib/postmen.rb
|
162
162
|
- lib/postmen/collection_proxy.rb
|
163
163
|
- lib/postmen/connection.rb
|
164
|
+
- lib/postmen/errors.rb
|
164
165
|
- lib/postmen/label.rb
|
165
166
|
- lib/postmen/label_collection.rb
|
166
167
|
- lib/postmen/manifest.rb
|