easyship 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e185adc98f576e3cf15ffc1ca38edf2dca8a0ffa580f68a731c900c3632392b
4
- data.tar.gz: e15d52b3f530c58883fb8f50b086db537939ceed2fc1afff3579ea6aa82373c1
3
+ metadata.gz: 7b584f647a6c1e9cd0379a94b3fc479c8f82691ab1ff8a36d797dae1c24e9c89
4
+ data.tar.gz: 5f288ce157f0b0b1c5e19f6c8a0a7851bf2bf1c5acb1c22b6660656ceed10204
5
5
  SHA512:
6
- metadata.gz: 707860b193dbc25e916f8d0e5e68a2a3c8e34498e523871e243cf487f1e5c4c2469ed274099899b1b50c22598dc085906eca132f9e537515c43bf03428040c02
7
- data.tar.gz: ec38670ff9d6626bc62485d8c836d00c1efb8e4a8218214c5c6b36b01570ad3b71906511c2459dc4a74b3a5ed91e3d3f91bd5f07586e75d481dc2ebf142a4d9a
6
+ metadata.gz: 22a0cbabb4582b714d56827fdd6f29bee92958900b2204ba3fce15a62ed85139e327dcfaa39dcf3f935cdeab0440424fa00bf044f003282ac9212837c97a83a2
7
+ data.tar.gz: fd30c1f4d75e89f2cc01ea8b97040cd19717af6f5e7d6bdb26a661507de197882be0f10f9cfaae2f49ed92d65e8aa5c8cd9f6ee3b24e4ef747da158012a94abc
data/.rubocop.yml CHANGED
@@ -12,3 +12,6 @@ Style/Copyright:
12
12
 
13
13
  RSpec/ExampleLength:
14
14
  Max: 10
15
+
16
+ RSpec/NestedGroups:
17
+ Max: 5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [v0.4.0](https://github.com/mmarusyk/easyship/tree/v0.4.0) - 2026-01-24
4
+
5
+ ### Added
6
+ - Support for custom headers by @mmarusyk in https://github.com/mmarusyk/easyship/pull/14
7
+
3
8
  ## [v0.3.0](https://github.com/mmarusyk/easyship/tree/v0.3.0) - 2025-11-29
4
9
 
5
10
  ### Added
data/README.md CHANGED
@@ -58,10 +58,10 @@ Easyship.configure do |config|
58
58
  end
59
59
  ```
60
60
 
61
- Configuration supports the next keys: `url`, `api_key`, `per_page`, `requests_per_second`, `requests_per_minute`.
61
+ Configuration supports the next keys: `url`, `api_key`, `per_page`, `requests_per_second`, `requests_per_minute`, `headers`.
62
62
 
63
63
  ### Making Requests
64
- `Easyship::Client` supports the next methods: `get`, `post`, `put`, `delete`.
64
+ `Easyship::Client` supports the next methods: `get`, `post`, `put`, `patch`, `delete`.
65
65
  ```ruby
66
66
  Easyship::Client.instance.get('/2023-01/account')
67
67
  ```
@@ -174,6 +174,104 @@ Easyship::Client.instance.get('/2023-01/shipments', {
174
174
  end
175
175
  ```
176
176
 
177
+ ### Custom Headers
178
+
179
+ You can pass custom headers both globally (via configuration) and per-request.
180
+
181
+ **Global Headers (via Configuration):**
182
+
183
+ ```ruby
184
+ Easyship.configure do |config|
185
+ config.url = 'api_url'
186
+ config.api_key = 'your_easyship_api_key'
187
+ config.headers = {
188
+ 'X-Custom-Header' => 'custom-value'
189
+ }
190
+ end
191
+ ```
192
+
193
+ **Per-Request Headers:**
194
+
195
+ ```ruby
196
+ # Override or add headers for a specific request
197
+ Easyship::Client.instance.get('/2023-01/account', {}, headers: {
198
+ 'X-Request-ID' => 'unique-request-id'
199
+ })
200
+
201
+ # POST with custom headers
202
+ Easyship::Client.instance.post('/2023-01/shipment', payload, headers: {
203
+ 'X-Idempotency-Key' => 'unique-key'
204
+ })
205
+
206
+ # PUT with custom headers
207
+ Easyship::Client.instance.put('/2023-01/shipment/123', payload, headers: {
208
+ 'X-Custom-Header' => 'value'
209
+ })
210
+
211
+ # PATCH with custom headers
212
+ Easyship::Client.instance.patch('/2023-01/shipment/123', payload, headers: {
213
+ 'X-Custom-Header' => 'value'
214
+ })
215
+
216
+ # DELETE with custom headers
217
+ Easyship::Client.instance.delete('/2023-01/shipment/123', {}, headers: {
218
+ 'X-Custom-Header' => 'value'
219
+ })
220
+ ```
221
+
222
+ **Note:** Per-request headers will override global headers if the same header key is used.
223
+
224
+ ### Using Idempotency Keys
225
+
226
+ Idempotency keys are essential for safely retrying requests without accidentally performing the same operation twice. This is particularly important for POST requests that create resources (like shipments, orders, or payments).
227
+
228
+ **Example - Creating a Shipment with Idempotency:**
229
+
230
+ ```ruby
231
+ # Generate a unique key (e.g., UUID, database record ID, or any unique identifier)
232
+ idempotency_key = SecureRandom.uuid
233
+
234
+ payload = {
235
+ origin_country_alpha2: "SG",
236
+ destination_country_alpha2: "US",
237
+ tax_paid_by: "Recipient",
238
+ is_insured: false,
239
+ items: [
240
+ {
241
+ description: "Product",
242
+ actual_weight: 1.2,
243
+ height: 10,
244
+ width: 15,
245
+ length: 20,
246
+ declared_currency: "USD",
247
+ declared_customs_value: 50
248
+ }
249
+ ]
250
+ }
251
+
252
+ begin
253
+ response = Easyship::Client.instance.post(
254
+ '/2023-01/shipments',
255
+ payload,
256
+ headers: { 'X-Idempotency-Key' => idempotency_key }
257
+ )
258
+
259
+ # If this request fails due to network issues and you retry with the same key,
260
+ # the API will return the same shipment without creating a duplicate
261
+ rescue Easyship::Errors::EasyshipError => e
262
+ # Safe to retry with the same idempotency_key
263
+ retry
264
+ end
265
+ ```
266
+
267
+ **Best Practices:**
268
+
269
+ - Use unique, random keys (UUIDs are recommended)
270
+ - Store the idempotency key with your order/shipment record in your database
271
+ - Reuse the same key when retrying a failed request
272
+ - Don't reuse keys across different operations or resources
273
+ - Keys typically expire after 24 hours (check API documentation)
274
+
177
275
  ## Development
178
276
 
179
277
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. Then, eun `rake rubocop` to run the rubocop. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -16,46 +16,65 @@ module Easyship
16
16
  @api_key = Easyship.configuration.api_key
17
17
  end
18
18
 
19
- def get(path, params = {}, &block)
19
+ def get(path, params = {}, headers: {}, &block)
20
20
  if block
21
21
  Easyship::Pagination::Cursor.new(self, path, params).all(&block)
22
22
  else
23
- response = connection.get(path, params)
23
+ response = connection(headers).get(path, params)
24
24
 
25
25
  handle_response(response)
26
26
  end
27
27
  end
28
28
 
29
- def post(path, params = {})
30
- response = connection.post(path, params.to_json)
29
+ def post(path, params = {}, headers: {})
30
+ response = connection(headers).post(path, params.to_json)
31
31
 
32
32
  handle_response(response)
33
33
  end
34
34
 
35
- def put(path, params = {})
36
- response = connection.put(path, params.to_json)
35
+ def put(path, params = {}, headers: {})
36
+ response = connection(headers).put(path, params.to_json)
37
37
 
38
38
  handle_response(response)
39
39
  end
40
40
 
41
- def delete(path, params = {})
42
- response = connection.delete(path, params)
41
+ def delete(path, params = {}, headers: {})
42
+ response = connection(headers).delete(path, params)
43
+
44
+ handle_response(response)
45
+ end
46
+
47
+ def patch(path, params = {}, headers: {})
48
+ response = connection(headers).patch(path, params.to_json)
43
49
 
44
50
  handle_response(response)
45
51
  end
46
52
 
47
53
  private
48
54
 
49
- def connection
55
+ def connection(custom_headers = {})
50
56
  Faraday.new(url: @url) do |faraday|
51
57
  faraday.request :url_encoded
52
58
  faraday.adapter Faraday.default_adapter
53
59
  faraday.headers['Authorization'] = "Bearer #{@api_key}"
54
60
  faraday.headers['Content-Type'] = 'application/json'
61
+ merge_headers(faraday, custom_headers)
55
62
  faraday.use Easyship::Middleware::ErrorHandlerMiddleware
56
63
  end
57
64
  end
58
65
 
66
+ def merge_headers(faraday, custom_headers)
67
+ # Merge global configuration headers
68
+ Easyship.configuration.headers.each do |key, value|
69
+ faraday.headers[key] = value
70
+ end
71
+
72
+ # Merge request-specific headers (override globals)
73
+ custom_headers.each do |key, value|
74
+ faraday.headers[key] = value
75
+ end
76
+ end
77
+
59
78
  def handle_response(response)
60
79
  Easyship::Handlers::ResponseBodyHandler.handle_response(response)
61
80
  end
@@ -3,7 +3,7 @@
3
3
  module Easyship
4
4
  # Represents the configuration settings for the Easyship client.
5
5
  class Configuration
6
- attr_accessor :url, :api_key, :per_page, :requests_per_second, :requests_per_minute
6
+ attr_accessor :url, :api_key, :per_page, :requests_per_second, :requests_per_minute, :headers
7
7
 
8
8
  def initialize
9
9
  @url = nil
@@ -11,6 +11,7 @@ module Easyship
11
11
  @per_page = 100 # Maximum possible number of items per page
12
12
  @requests_per_second = nil
13
13
  @requests_per_minute = nil
14
+ @headers = {}
14
15
  end
15
16
  end
16
17
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Easyship
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easyship
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Marusyk
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-01-24 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: faraday
@@ -69,6 +70,7 @@ metadata:
69
70
  allowed_push_host: https://rubygems.org
70
71
  source_code_uri: https://github.com/mmarusyk/easyship
71
72
  changelog_uri: https://github.com/mmarusyk/easyship/blob/main/CHANGELOG.md
73
+ post_install_message:
72
74
  rdoc_options: []
73
75
  require_paths:
74
76
  - lib
@@ -83,7 +85,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
85
  - !ruby/object:Gem::Version
84
86
  version: '0'
85
87
  requirements: []
86
- rubygems_version: 3.6.9
88
+ rubygems_version: 3.5.22
89
+ signing_key:
87
90
  specification_version: 4
88
91
  summary: A Ruby client for integrating with Easyship's API for shipping and logistics
89
92
  management.