after_ship 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/ollie/after_ship.svg?branch=master)](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
|