after_ship 0.0.2 → 0.0.4
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/.travis.yml +1 -1
- data/README.md +69 -32
- data/after_ship.gemspec +4 -4
- data/lib/after_ship/checkpoint.rb +35 -28
- data/lib/after_ship/core/attributes.rb +14 -0
- data/lib/after_ship/core/date_utils.rb +76 -0
- data/lib/after_ship/core/error.rb +29 -0
- data/lib/after_ship/core/error_handler.rb +67 -0
- data/lib/after_ship/core/request.rb +131 -0
- data/lib/after_ship/core/version.rb +4 -0
- data/lib/after_ship/courier.rb +45 -0
- data/lib/after_ship/tracking.rb +78 -6
- data/lib/after_ship.rb +158 -214
- data/spec/integration/after_ship_spec.rb +40 -0
- data/spec/request_stubs.rb +30 -97
- data/spec/requests/couriers.json +50 -0
- data/spec/requests/tracking/created.json +53 -0
- data/spec/requests/tracking/{delivered_ok.json → delivered.json} +79 -65
- data/spec/requests/trackings.json +654 -0
- data/spec/units/after_ship_spec.rb +104 -0
- data/spec/units/checkpoint_spec.rb +135 -0
- data/spec/units/courier_spec.rb +41 -0
- data/spec/{lib → units}/date_utils_spec.rb +17 -9
- data/spec/units/error_handler_spec.rb +168 -0
- data/spec/units/request_spec.rb +190 -0
- data/spec/units/tracking_spec.rb +276 -0
- metadata +39 -25
- data/lib/after_ship/version.rb +0 -3
- data/lib/attributes.rb +0 -12
- data/lib/date_utils.rb +0 -61
- data/spec/lib/after_ship_spec.rb +0 -137
- data/spec/lib/checkpoint_spec.rb +0 -139
- data/spec/lib/tracking_spec.rb +0 -89
- data/spec/requests/tracking/delivered_wild.json +0 -653
- data/spec/requests/tracking/in_transit.json +0 -443
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3060bd34a3212af9a3fc8d11f6639218eb721a21
|
4
|
+
data.tar.gz: 6cc52a30fd7414efb6cfe67a91dd1823191bda4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a40b8f5a968c21b2c61fbe139c729ced7fd0d4ea66930fb1d8fbece394bdf0504d009e20b1d0090fe1cb7083119220230c57d607ac24eeaef0bfbd19efa1054d
|
7
|
+
data.tar.gz: 3bf32a786e3dcd6846363fa46035b67855aa312b46ff804c81570e73b4e07737bc11f6fe8aa9bc5cb59d559424f438e6d7f93a515cc4fd74faa899318b284684
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/ollie/after_ship)
|
4
4
|
|
5
|
-
A smallish library to talking to AfterShip via
|
5
|
+
A smallish library to talking to AfterShip via v4 API.
|
6
6
|
|
7
|
-
You will need an AfterShip API key, see here https://www.aftership.com/docs/api/
|
7
|
+
You will need an AfterShip API key, see here https://www.aftership.com/docs/api/4.
|
8
8
|
The JSON is parsed by MultiJson (https://github.com/intridea/multi_json) so
|
9
9
|
you may want to drop in your favorite JSON engine.
|
10
10
|
|
@@ -29,7 +29,7 @@ client = AfterShip.new(api_key: 'your-aftership-api-key')
|
|
29
29
|
```
|
30
30
|
|
31
31
|
Get a list of trackings
|
32
|
-
https://www.aftership.com/docs/api/
|
32
|
+
https://www.aftership.com/docs/api/4/trackings/get-trackings
|
33
33
|
|
34
34
|
```ruby
|
35
35
|
client.trackings
|
@@ -44,75 +44,112 @@ client.trackings
|
|
44
44
|
```
|
45
45
|
|
46
46
|
Get a tracking
|
47
|
-
https://www.aftership.com/docs/api/
|
47
|
+
https://www.aftership.com/docs/api/4/trackings/get-trackings-slug-tracking_number
|
48
48
|
|
49
49
|
```ruby
|
50
50
|
client.tracking('tracking-number', 'ups')
|
51
51
|
|
52
|
-
# Will return Tracking object or raise AfterShip::
|
53
|
-
# if not exists:
|
52
|
+
# Will return Tracking object or raise AfterShip::Error::NotFound:
|
54
53
|
|
55
|
-
#<AfterShip::Tracking:
|
54
|
+
#<AfterShip::Tracking:0x007f838ef44e58
|
56
55
|
@active=false,
|
56
|
+
@android=[],
|
57
57
|
@courier="UPS",
|
58
|
-
@created_at=#<DateTime: 2014-
|
59
|
-
@updated_at=#<DateTime: 2014-07-18T09:00:47+00:00 ((2456857j,32447s,0n),+0s,2299161j)>>
|
58
|
+
@created_at=#<DateTime: 2014-11-19T15:16:17+00:00 ...>,
|
60
59
|
@custom_fields={},
|
61
60
|
@customer_name=nil,
|
61
|
+
@delivery_time=8,
|
62
62
|
@destination_country_iso3="USA",
|
63
63
|
@emails=[],
|
64
64
|
@expected_delivery=nil,
|
65
|
-
@
|
65
|
+
@id="546cb4414a1a2097122ae7b1",
|
66
|
+
@ios=[],
|
67
|
+
@order_id="PL-66448782",
|
66
68
|
@order_id_path=nil,
|
67
69
|
@origin_country_iso3="IND",
|
68
|
-
@shipment_package_count=
|
69
|
-
@shipment_type="
|
70
|
-
@
|
70
|
+
@shipment_package_count=1,
|
71
|
+
@shipment_type="UPS SAVER",
|
72
|
+
@shipment_weight=0.5,
|
73
|
+
@shipment_weight_unit="kg",
|
74
|
+
@signed_by="MET CUSTOM",
|
71
75
|
@slug="ups",
|
72
76
|
@smses=[],
|
73
77
|
@source="api",
|
74
78
|
@status="Delivered",
|
75
79
|
@tag="Delivered",
|
76
|
-
@title="
|
77
|
-
@tracked_count=
|
78
|
-
@
|
79
|
-
@
|
80
|
+
@title="1ZA2207X0490715335",
|
81
|
+
@tracked_count=6,
|
82
|
+
@tracking_account_number=nil,
|
83
|
+
@tracking_number="1ZA2207X0490715335",
|
84
|
+
@tracking_postal_code=nil,
|
85
|
+
@tracking_ship_date=nil,
|
86
|
+
@unique_token="-y6ziF438",
|
87
|
+
@updated_at=#<DateTime: 2014-11-19T22:12:32+00:00 ...>,
|
80
88
|
@checkpoints=[
|
81
|
-
#<AfterShip::Checkpoint:
|
82
|
-
@checkpoint_time
|
83
|
-
|
89
|
+
#<AfterShip::Checkpoint:0x007f838ef57d50
|
90
|
+
@checkpoint_time=
|
91
|
+
#<DateTime: 2014-11-11T19:12:00+00:00 ...>,
|
92
|
+
@city="MUMBAI",
|
84
93
|
@country_iso3=nil,
|
85
|
-
@country_name="
|
94
|
+
@country_name="IN",
|
86
95
|
@courier="UPS",
|
87
|
-
@created_at
|
88
|
-
|
96
|
+
@created_at=
|
97
|
+
#<DateTime: 2014-11-19T15:16:17+00:00 ...>,
|
98
|
+
@message="PICKUP SCAN",
|
89
99
|
@slug="ups",
|
90
|
-
@state=
|
91
|
-
@status="
|
92
|
-
@tag="
|
93
|
-
@zip=
|
100
|
+
@state=nil,
|
101
|
+
@status="In Transit",
|
102
|
+
@tag="InTransit",
|
103
|
+
@zip=nil>,
|
94
104
|
#<AfterShip::Checkpoint ...>,
|
95
105
|
...
|
96
|
-
]
|
106
|
+
]
|
107
|
+
>
|
97
108
|
```
|
98
109
|
|
99
110
|
Create a new tracking
|
100
|
-
https://www.aftership.com/docs/api/
|
111
|
+
https://www.aftership.com/docs/api/4/trackings/post-trackings
|
101
112
|
|
102
113
|
```ruby
|
103
114
|
client.create_tracking('tracking-number', 'ups', order_id: 'external-id')
|
104
115
|
|
105
|
-
# Will return Tracking object or raise
|
106
|
-
#
|
116
|
+
# Will return Tracking object or raise
|
117
|
+
# AfterShip::Error::TrackingAlreadyExists:
|
107
118
|
|
108
119
|
#<AfterShip::Tracking ...>
|
109
120
|
```
|
110
121
|
|
111
122
|
Update a tracking
|
112
|
-
https://www.aftership.com/docs/api/
|
123
|
+
https://www.aftership.com/docs/api/4/trackings/put-trackings-slug-tracking_number
|
113
124
|
|
114
125
|
```ruby
|
115
126
|
client.update_tracking('tracking-number', 'ups', order_id: 'external-id')
|
127
|
+
|
128
|
+
# Will return Tracking object or raise
|
129
|
+
# AfterShip::Error::TrackingAlreadyExists:
|
130
|
+
|
131
|
+
#<AfterShip::Tracking ...>
|
132
|
+
```
|
133
|
+
|
134
|
+
Get activated couriers
|
135
|
+
https://www.aftership.com/docs/api/4/couriers/get-couriers
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
client.couriers
|
139
|
+
|
140
|
+
# Will return list of Courier objects:
|
141
|
+
|
142
|
+
[
|
143
|
+
#<AfterShip::Courier:0x007fa2771d4bf8
|
144
|
+
@name="USPS",
|
145
|
+
@other_name="United States Postal Service",
|
146
|
+
@phone="+1 800-275-8777",
|
147
|
+
@required_fields=[],
|
148
|
+
@slug="usps",
|
149
|
+
@web_url="https://www.usps.com">,
|
150
|
+
#<AfterShip::Courier ...>
|
151
|
+
...
|
152
|
+
]
|
116
153
|
```
|
117
154
|
|
118
155
|
## Contributing
|
data/after_ship.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'after_ship/version'
|
4
|
+
require 'after_ship/core/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'after_ship'
|
8
8
|
spec.version = AfterShip::VERSION
|
9
9
|
spec.authors = ['Oldrich Vetesnik']
|
10
10
|
spec.email = ['oldrich.vetesnik@gmail.com']
|
11
|
-
spec.summary = 'A smallish library to talking to AfterShip via
|
11
|
+
spec.summary = 'A smallish library to talking to AfterShip via v4 API.'
|
12
12
|
spec.homepage = 'https://github.com/ollie/after_ship'
|
13
13
|
spec.license = 'MIT'
|
14
14
|
|
@@ -22,11 +22,11 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
# Test
|
24
24
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
25
|
-
spec.add_development_dependency 'webmock', '~> 1.
|
25
|
+
spec.add_development_dependency 'webmock', '~> 1.20'
|
26
26
|
spec.add_development_dependency 'simplecov', '~> 0.9'
|
27
27
|
|
28
28
|
# Code style, debugging, docs
|
29
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 0.27'
|
30
30
|
spec.add_development_dependency 'pry', '~> 0.10'
|
31
31
|
spec.add_development_dependency 'yard', '~> 0.8'
|
32
32
|
spec.add_development_dependency 'rake', '~> 10.3'
|
@@ -1,42 +1,48 @@
|
|
1
1
|
class AfterShip
|
2
2
|
# Wrapper object for AfterShip tracking checkpoint:
|
3
|
-
# https://www.aftership.com/docs/api/
|
3
|
+
# https://www.aftership.com/docs/api/4/trackings/get-trackings-slug-tracking_number
|
4
4
|
class Checkpoint
|
5
5
|
include Attributes
|
6
6
|
|
7
|
-
#
|
7
|
+
# Date and time of the tracking created.
|
8
8
|
#
|
9
9
|
# Should always be available.
|
10
10
|
#
|
11
|
-
# @return [
|
12
|
-
attr_reader :
|
11
|
+
# @return [DateTime]
|
12
|
+
attr_reader :created_at
|
13
13
|
|
14
|
-
#
|
14
|
+
# The unique code of courier for this checkpoint message.
|
15
15
|
#
|
16
|
-
#
|
16
|
+
# Should always be available.
|
17
17
|
#
|
18
18
|
# @return [String]
|
19
|
-
|
19
|
+
attr_reader :slug
|
20
20
|
|
21
|
-
# Courier name
|
21
|
+
# Courier name.
|
22
|
+
#
|
23
|
+
# Custom method!
|
22
24
|
#
|
23
25
|
# @return [String]
|
24
26
|
attr_accessor :courier
|
25
27
|
|
26
|
-
# Date and time of the
|
28
|
+
# Date and time of the checkpoint, provided by courier.
|
29
|
+
#
|
30
|
+
# Empty String,
|
31
|
+
# YYYY-MM-DD,
|
32
|
+
# YYYY-MM-DDTHH:MM:SS, or
|
33
|
+
# YYYY-MM-DDTHH:MM:SS+TIMEZONE.
|
27
34
|
#
|
28
35
|
# Should always be available.
|
29
36
|
#
|
30
37
|
# @return [DateTime]
|
31
|
-
attr_reader :
|
38
|
+
attr_reader :checkpoint_time
|
32
39
|
|
33
|
-
#
|
34
|
-
# Seems to be Alpha-2 code, e.g. +IN+, +DE+.
|
40
|
+
# Location info (if any).
|
35
41
|
#
|
36
42
|
# May be empty.
|
37
43
|
#
|
38
44
|
# @return [String]
|
39
|
-
attr_accessor :
|
45
|
+
attr_accessor :city
|
40
46
|
|
41
47
|
# Country ISO Alpha-3 (three letters) of the checkpoint.
|
42
48
|
#
|
@@ -45,6 +51,14 @@ class AfterShip
|
|
45
51
|
# @return [String]
|
46
52
|
attr_accessor :country_iso3
|
47
53
|
|
54
|
+
# Country name of the checkpoint, may also contain other location info.
|
55
|
+
# Seems to be Alpha-2 code, e.g. +IN+, +DE+.
|
56
|
+
#
|
57
|
+
# May be empty.
|
58
|
+
#
|
59
|
+
# @return [String]
|
60
|
+
attr_accessor :country_name
|
61
|
+
|
48
62
|
# Checkpoint message
|
49
63
|
#
|
50
64
|
# Should always be available.
|
@@ -52,6 +66,13 @@ class AfterShip
|
|
52
66
|
# @return [String]
|
53
67
|
attr_accessor :message
|
54
68
|
|
69
|
+
# Location info (if any).
|
70
|
+
#
|
71
|
+
# May be empty.
|
72
|
+
#
|
73
|
+
# @return [String]
|
74
|
+
attr_accessor :state
|
75
|
+
|
55
76
|
# Status of the checkpoint.
|
56
77
|
#
|
57
78
|
# Should always be available.
|
@@ -73,20 +94,6 @@ class AfterShip
|
|
73
94
|
# @return [String]
|
74
95
|
attr_accessor :status
|
75
96
|
|
76
|
-
# Date and time of the checkpoint, provided by courier.
|
77
|
-
#
|
78
|
-
# Should always be available.
|
79
|
-
#
|
80
|
-
# @return [DateTime]
|
81
|
-
attr_reader :checkpoint_time
|
82
|
-
|
83
|
-
# Location info (if any).
|
84
|
-
#
|
85
|
-
# May be empty.
|
86
|
-
#
|
87
|
-
# @return [String]
|
88
|
-
attr_accessor :state
|
89
|
-
|
90
97
|
# Location info (if any).
|
91
98
|
#
|
92
99
|
# May be empty.
|
@@ -101,7 +108,7 @@ class AfterShip
|
|
101
108
|
load_attributes(data)
|
102
109
|
end
|
103
110
|
|
104
|
-
#
|
111
|
+
# The unique code of courier for this checkpoint message.
|
105
112
|
#
|
106
113
|
# Should always be available.
|
107
114
|
#
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class AfterShip
|
2
|
+
# Extracted attributes loading.
|
3
|
+
module Attributes
|
4
|
+
# Loop through the data hash and for each key call a setter with the value.
|
5
|
+
#
|
6
|
+
# @param data [Hash]
|
7
|
+
def load_attributes(data)
|
8
|
+
data.each do |attribute, value|
|
9
|
+
setter = "#{ attribute }="
|
10
|
+
send(setter, value) if respond_to?(setter)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class AfterShip
|
2
|
+
# Simple utility class for parsing dates and datetimes.
|
3
|
+
module DateUtils
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Date:
|
7
|
+
#
|
8
|
+
# +YYYYMMDD+
|
9
|
+
DATE_PLAIN_REGEX = /
|
10
|
+
\A
|
11
|
+
\d{4}\d{2}\d{2}
|
12
|
+
\z
|
13
|
+
/x
|
14
|
+
|
15
|
+
# Date:
|
16
|
+
#
|
17
|
+
# +YYYY-MM-DD+
|
18
|
+
DATE_REGEX = /
|
19
|
+
\A
|
20
|
+
\d{4}-\d{2}-\d{2}
|
21
|
+
\z
|
22
|
+
/x
|
23
|
+
|
24
|
+
# Datetime without zone:
|
25
|
+
#
|
26
|
+
# +YYYY-MM-DDTHH:MM:SS+
|
27
|
+
DATETIME_REGEX = /
|
28
|
+
\A
|
29
|
+
\d{4}-\d{2}-\d{2}
|
30
|
+
T
|
31
|
+
\d{2}:\d{2}:\d{2}
|
32
|
+
\z
|
33
|
+
/x
|
34
|
+
|
35
|
+
# Datetime with zone:
|
36
|
+
#
|
37
|
+
# +YYYY-MM-DDTHH:MM:SSZ+
|
38
|
+
# +YYYY-MM-DDTHH:MM:SS+HH:MM+
|
39
|
+
# +YYYY-MM-DDTHH:MM:SS-HH:MM+
|
40
|
+
DATETIME_WITH_ZONE_REGEX = /
|
41
|
+
\A
|
42
|
+
\d{4}-\d{2}-\d{2}
|
43
|
+
T
|
44
|
+
\d{2}:\d{2}:\d{2}
|
45
|
+
(Z|[+-]\d{2}:\d{2})
|
46
|
+
\z
|
47
|
+
/x
|
48
|
+
|
49
|
+
# Try to parse a date or datetime from a string.
|
50
|
+
#
|
51
|
+
# @param value [String]
|
52
|
+
# Empty String,
|
53
|
+
# YYYY-MM-DD,
|
54
|
+
# YYYY-MM-DDTHH:MM:SS,
|
55
|
+
# YYYY-MM-DDTHH:MM:SSZ,
|
56
|
+
# YYYY-MM-DDTHH:MM:SS+HH:MM or
|
57
|
+
# YYYY-MM-DDTHH:MM:SS-HH:MM.
|
58
|
+
#
|
59
|
+
def parse(value)
|
60
|
+
case value
|
61
|
+
when ''
|
62
|
+
nil
|
63
|
+
when nil
|
64
|
+
nil
|
65
|
+
when DATE_PLAIN_REGEX
|
66
|
+
Date.parse(value)
|
67
|
+
when DATE_REGEX
|
68
|
+
Date.parse(value)
|
69
|
+
when DATETIME_REGEX, DATETIME_WITH_ZONE_REGEX
|
70
|
+
DateTime.parse(value)
|
71
|
+
else
|
72
|
+
fail ArgumentError, "Invalid expected_delivery date #{ value.inspect }"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class AfterShip
|
2
|
+
# Error classes.
|
3
|
+
# https://www.aftership.com/docs/api/4/errors
|
4
|
+
class Error < StandardError
|
5
|
+
class BadRequest < Error; end # 400
|
6
|
+
class InvalidJsonData < BadRequest; end # 4001, 4002
|
7
|
+
class TrackingAlreadyExists < BadRequest; end # 4003
|
8
|
+
class TrackingDoesNotExist < BadRequest; end # 4004
|
9
|
+
class TrackingNumberInvalid < BadRequest; end # 4005
|
10
|
+
class TrackingObjectRequired < BadRequest; end # 4006
|
11
|
+
class TrackingNumberRequired < BadRequest; end # 4007
|
12
|
+
class FieldInvalid < BadRequest; end # 4008
|
13
|
+
class FieldRequired < BadRequest; end # 4009
|
14
|
+
class SlugInvalid < BadRequest; end # 4010
|
15
|
+
class CourierFieldInvalid < BadRequest; end # 4011
|
16
|
+
class CourierNotDetected < BadRequest; end # 4012
|
17
|
+
class RetrackNotAllowed < BadRequest; end # 4013, 4016
|
18
|
+
class NotificationRequired < BadRequest; end # 4014
|
19
|
+
class IdInvalid < BadRequest; end # 4015
|
20
|
+
class Unauthorized < Error; end # 401
|
21
|
+
class Forbidden < Error; end # 403
|
22
|
+
class NotFound < Error; end # 404
|
23
|
+
class TooManyRequests < Error; end # 429
|
24
|
+
class InternalError < Error; end # 500, 502, 503, 504
|
25
|
+
|
26
|
+
class UnknownError < Error; end # Huh?
|
27
|
+
class Timeout < Error; end # Uh oh.
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class AfterShip
|
2
|
+
# Response handling logic.
|
3
|
+
module ErrorHandler
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# These mean that the response is good.
|
7
|
+
SUCCESS_CODES = [200, 201]
|
8
|
+
|
9
|
+
# Map meta codes to error classes.
|
10
|
+
CODE_TO_ERROR_MAP = {
|
11
|
+
400 => Error::BadRequest,
|
12
|
+
4001 => Error::InvalidJsonData,
|
13
|
+
4002 => Error::InvalidJsonData,
|
14
|
+
4003 => Error::TrackingAlreadyExists,
|
15
|
+
4004 => Error::TrackingDoesNotExist,
|
16
|
+
4005 => Error::TrackingNumberInvalid,
|
17
|
+
4006 => Error::TrackingObjectRequired,
|
18
|
+
4007 => Error::TrackingNumberRequired,
|
19
|
+
4008 => Error::FieldInvalid,
|
20
|
+
4009 => Error::FieldRequired,
|
21
|
+
4010 => Error::SlugInvalid,
|
22
|
+
4011 => Error::CourierFieldInvalid,
|
23
|
+
4012 => Error::CourierNotDetected,
|
24
|
+
4013 => Error::RetrackNotAllowed,
|
25
|
+
4016 => Error::RetrackNotAllowed,
|
26
|
+
4014 => Error::NotificationRequired,
|
27
|
+
4015 => Error::IdInvalid,
|
28
|
+
401 => Error::Unauthorized,
|
29
|
+
403 => Error::Forbidden,
|
30
|
+
404 => Error::NotFound,
|
31
|
+
429 => Error::TooManyRequests,
|
32
|
+
500 => Error::InternalError,
|
33
|
+
502 => Error::InternalError,
|
34
|
+
503 => Error::InternalError,
|
35
|
+
504 => Error::InternalError
|
36
|
+
}
|
37
|
+
|
38
|
+
# Did it timeout? If the body empty?
|
39
|
+
#
|
40
|
+
# @param response [Typhoeus::Response]
|
41
|
+
def precheck(response)
|
42
|
+
fail Error::Timeout, "#{ response.effective_url } cannot be reached" if
|
43
|
+
response.timed_out?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Check the meta code of the response. If it isn't 200 or 201, raise an
|
47
|
+
# error.
|
48
|
+
#
|
49
|
+
# @param meta [Hash]
|
50
|
+
# @option meta code [Fixnum]
|
51
|
+
# @option meta message [String, nil]
|
52
|
+
# @option meta type [String, nil]
|
53
|
+
def check(meta)
|
54
|
+
code = meta.fetch(:code)
|
55
|
+
|
56
|
+
return if SUCCESS_CODES.include?(code)
|
57
|
+
|
58
|
+
error_class = error_class_for(code)
|
59
|
+
fail error_class, meta[:message]
|
60
|
+
end
|
61
|
+
|
62
|
+
# Pick the corresponding error class for the code.
|
63
|
+
def error_class_for(code)
|
64
|
+
CODE_TO_ERROR_MAP[code] || Error::UnknownError
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
class AfterShip
|
2
|
+
# Gather necessary pieces, assemble a `Typhoeus::Request`, run that,
|
3
|
+
# get a `Typhoeus::Response`, parse that, check for errors, return the
|
4
|
+
# parse JSON.
|
5
|
+
class Request
|
6
|
+
# Shorthand for GET request:
|
7
|
+
#
|
8
|
+
# request = Request.new(url: '...', api_key: '...', method: :get)
|
9
|
+
# response = request.response
|
10
|
+
#
|
11
|
+
# @param options [Hash]
|
12
|
+
# @option options api_key [String] Your API key.
|
13
|
+
# @option options url [String] The full endpoint URL.
|
14
|
+
# @option options body [Hash, nil] Body for the request as a hash.
|
15
|
+
#
|
16
|
+
# @return [Hash]
|
17
|
+
def self.get(options, &block)
|
18
|
+
options[:method] = :get
|
19
|
+
new(options, &block).response
|
20
|
+
end
|
21
|
+
|
22
|
+
# Shorthand for POST request:
|
23
|
+
#
|
24
|
+
# request = Request.new(url: '...', api_key: '...', method: :post)
|
25
|
+
# response = request.response
|
26
|
+
#
|
27
|
+
# @param options [Hash]
|
28
|
+
# @option options api_key [String] Your API key.
|
29
|
+
# @option options url [String] The full endpoint URL.
|
30
|
+
# @option options body [Hash, nil] Body for the request as a hash.
|
31
|
+
#
|
32
|
+
# @return [Hash]
|
33
|
+
def self.post(options, &block)
|
34
|
+
options[:method] = :post
|
35
|
+
new(options, &block).response
|
36
|
+
end
|
37
|
+
|
38
|
+
# Shorthand for PUT request:
|
39
|
+
#
|
40
|
+
# request = Request.new(url: '...', api_key: '...', method: :put)
|
41
|
+
# response = request.response
|
42
|
+
#
|
43
|
+
# @param options [Hash]
|
44
|
+
# @option options api_key [String] Your API key.
|
45
|
+
# @option options url [String] The full endpoint URL.
|
46
|
+
# @option options body [Hash, nil] Body for the request as a hash.
|
47
|
+
#
|
48
|
+
# @return [Hash]
|
49
|
+
def self.put(options, &block)
|
50
|
+
options[:method] = :put
|
51
|
+
new(options, &block).response
|
52
|
+
end
|
53
|
+
|
54
|
+
# Prepare the request to be run later.
|
55
|
+
#
|
56
|
+
# @param options [Hash]
|
57
|
+
# @option options api_key [String] Your API key.
|
58
|
+
# @option options url [String] The full endpoint URL.
|
59
|
+
# @option options method [Symbol] The HTTP method.
|
60
|
+
# @option options body [Hash, nil] Body for the request as a hash.
|
61
|
+
# @param block [Proc] Response modifier callback.
|
62
|
+
def initialize(options = {}, &block)
|
63
|
+
@api_key = options.fetch(:api_key)
|
64
|
+
@url = options.fetch(:url)
|
65
|
+
@method = options.fetch(:method)
|
66
|
+
@body = options[:body]
|
67
|
+
@request = typhoeus_request
|
68
|
+
@block = block
|
69
|
+
end
|
70
|
+
|
71
|
+
# Do the request to the server and handle the response.
|
72
|
+
def response
|
73
|
+
response = typhoeus_response
|
74
|
+
ErrorHandler.precheck(response)
|
75
|
+
parsed_body = MultiJson.load(response.body, JSON_OPTIONS)
|
76
|
+
ErrorHandler.check(parsed_body.fetch(:meta))
|
77
|
+
|
78
|
+
if @block
|
79
|
+
@block.call(parsed_body)
|
80
|
+
else
|
81
|
+
parsed_body
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
# Run the `Typhoeus::Request` and return the response.
|
88
|
+
#
|
89
|
+
# @return [Typhoeus::Request]
|
90
|
+
def typhoeus_response
|
91
|
+
@request.run
|
92
|
+
end
|
93
|
+
|
94
|
+
# Make the `Typhoeus::Request` to be run later.
|
95
|
+
#
|
96
|
+
# @return [Typhoeus::Request]
|
97
|
+
def typhoeus_request
|
98
|
+
request = Typhoeus::Request.new(
|
99
|
+
@url,
|
100
|
+
method: @method,
|
101
|
+
headers: {
|
102
|
+
'aftership-api-key' => @api_key,
|
103
|
+
'Content-Type' => 'application/json'
|
104
|
+
}
|
105
|
+
)
|
106
|
+
|
107
|
+
request.options[:body] = MultiJson.dump(@body) if @body
|
108
|
+
make_verbose(request) if AfterShip.debug
|
109
|
+
|
110
|
+
request
|
111
|
+
end
|
112
|
+
|
113
|
+
# Print the low level cURL internals in the console as well as the
|
114
|
+
# request body and response body when it's available.
|
115
|
+
#
|
116
|
+
# @param request [Typhoeus::Request]
|
117
|
+
def make_verbose(request)
|
118
|
+
request.options[:verbose] = true
|
119
|
+
|
120
|
+
request.on_complete do |response|
|
121
|
+
puts
|
122
|
+
puts 'Request body:'
|
123
|
+
puts request.options[:body]
|
124
|
+
puts
|
125
|
+
puts 'Response body:'
|
126
|
+
puts response.body
|
127
|
+
puts
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|