sp_api_clients 2.0.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 +7 -0
- data/CHANGELOG.md +161 -0
- data/LICENSE +21 -0
- data/README.md +284 -0
- data/lib/amazon_sp_clients/adapter_loader.rb +28 -0
- data/lib/amazon_sp_clients/api_client.rb +309 -0
- data/lib/amazon_sp_clients/api_error.rb +37 -0
- data/lib/amazon_sp_clients/api_response.rb +54 -0
- data/lib/amazon_sp_clients/configuration.rb +144 -0
- data/lib/amazon_sp_clients/marketplaces.rb +63 -0
- data/lib/amazon_sp_clients/middlewares/raise_error.rb +166 -0
- data/lib/amazon_sp_clients/session.rb +124 -0
- data/lib/amazon_sp_clients/sp_fba_inventory.rb +8 -0
- data/lib/amazon_sp_clients/sp_feeds_2021.rb +8 -0
- data/lib/amazon_sp_clients/sp_fulfillment_outbound_2020.rb +8 -0
- data/lib/amazon_sp_clients/sp_listings_items_2021.rb +8 -0
- data/lib/amazon_sp_clients/sp_orders_v0.rb +8 -0
- data/lib/amazon_sp_clients/sp_reports_2021.rb +8 -0
- data/lib/amazon_sp_clients/sp_tokens_2021.rb +8 -0
- data/lib/amazon_sp_clients/sp_vdf_inventory_v1.rb +8 -0
- data/lib/amazon_sp_clients/sp_vdf_orders_v1.rb +8 -0
- data/lib/amazon_sp_clients/sp_vdf_shipping_v1.rb +8 -0
- data/lib/amazon_sp_clients/sp_vendor_invoices.rb +8 -0
- data/lib/amazon_sp_clients/sp_vendor_orders.rb +8 -0
- data/lib/amazon_sp_clients/sp_vendor_transaction_status.rb +8 -0
- data/lib/amazon_sp_clients/sp_vendors_shipments.rb +8 -0
- data/lib/amazon_sp_clients/token_exchange_auth.rb +82 -0
- data/lib/amazon_sp_clients/uploader.rb +77 -0
- data/lib/amazon_sp_clients/v2/api.rb +43 -0
- data/lib/amazon_sp_clients/v2/apis/fba_inventory.rb +80 -0
- data/lib/amazon_sp_clients/v2/apis/feeds_2021.rb +86 -0
- data/lib/amazon_sp_clients/v2/apis/fulfillment_outbound_2020.rb +184 -0
- data/lib/amazon_sp_clients/v2/apis/listings_items_2021.rb +144 -0
- data/lib/amazon_sp_clients/v2/apis/orders_v0.rb +165 -0
- data/lib/amazon_sp_clients/v2/apis/reports_2021.rb +117 -0
- data/lib/amazon_sp_clients/v2/apis/tokens_2021.rb +25 -0
- data/lib/amazon_sp_clients/v2/apis/vdf_inventory_v1.rb +26 -0
- data/lib/amazon_sp_clients/v2/apis/vdf_orders_v1.rb +61 -0
- data/lib/amazon_sp_clients/v2/apis/vdf_shipping_v1.rb +139 -0
- data/lib/amazon_sp_clients/v2/apis/vendor_invoices.rb +25 -0
- data/lib/amazon_sp_clients/v2/apis/vendor_orders.rb +106 -0
- data/lib/amazon_sp_clients/v2/apis/vendor_transaction_status.rb +25 -0
- data/lib/amazon_sp_clients/v2/apis/vendors_shipments.rb +120 -0
- data/lib/amazon_sp_clients/v2/apis.rb +82 -0
- data/lib/amazon_sp_clients/v2/client.rb +198 -0
- data/lib/amazon_sp_clients/v2/config.rb +85 -0
- data/lib/amazon_sp_clients/v2/credentials.rb +91 -0
- data/lib/amazon_sp_clients/v2/documents.rb +115 -0
- data/lib/amazon_sp_clients/v2/error_mapper.rb +235 -0
- data/lib/amazon_sp_clients/v2/errors.rb +117 -0
- data/lib/amazon_sp_clients/v2/lwa.rb +100 -0
- data/lib/amazon_sp_clients/v2/rdt.rb +104 -0
- data/lib/amazon_sp_clients/v2/token.rb +39 -0
- data/lib/amazon_sp_clients/v2.rb +33 -0
- data/lib/amazon_sp_clients/version.rb +3 -0
- data/lib/amazon_sp_clients.rb +69 -0
- data/lib/sp_api_clients.rb +6 -0
- data/sp_api_clients.gemspec +53 -0
- data/vendor/fba_inventory/lib/sp_fba_inventory/api/fba_inventory_api.rb +289 -0
- data/vendor/fba_inventory/lib/sp_fba_inventory.rb +12 -0
- data/vendor/feeds_2021/lib/sp_feeds_2021/api/feeds_api.rb +367 -0
- data/vendor/feeds_2021/lib/sp_feeds_2021.rb +12 -0
- data/vendor/fulfillment_outbound_2020/lib/sp_fulfillment_outbound_2020/api/fba_outbound_api.rb +845 -0
- data/vendor/fulfillment_outbound_2020/lib/sp_fulfillment_outbound_2020.rb +12 -0
- data/vendor/listings_items_2021/lib/sp_listings_items_2021/api/listings_api.rb +480 -0
- data/vendor/listings_items_2021/lib/sp_listings_items_2021.rb +12 -0
- data/vendor/orders_v0/lib/sp_orders_v0/api/orders_v0_api.rb +593 -0
- data/vendor/orders_v0/lib/sp_orders_v0/api/shipment_api.rb +83 -0
- data/vendor/orders_v0/lib/sp_orders_v0.rb +13 -0
- data/vendor/reports_2021/lib/sp_reports_2021/api/reports_api.rb +530 -0
- data/vendor/reports_2021/lib/sp_reports_2021.rb +12 -0
- data/vendor/tokens_2021/lib/sp_tokens_2021/api/tokens_api.rb +77 -0
- data/vendor/tokens_2021/lib/sp_tokens_2021.rb +12 -0
- data/vendor/vdf_inventory_v1/lib/sp_vdf_inventory_v1/api/update_inventory_api.rb +83 -0
- data/vendor/vdf_inventory_v1/lib/sp_vdf_inventory_v1.rb +12 -0
- data/vendor/vdf_orders_v1/lib/sp_vdf_orders_v1/api/vendor_orders_api.rb +217 -0
- data/vendor/vdf_orders_v1/lib/sp_vdf_orders_v1.rb +12 -0
- data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1/api/customer_invoices_api.rb +152 -0
- data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1/api/vendor_shipping_api.rb +264 -0
- data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1/api/vendor_shipping_labels_api.rb +208 -0
- data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1.rb +14 -0
- data/vendor/vendor_invoices/lib/sp_vendor_invoices/api/vendor_payments_api.rb +77 -0
- data/vendor/vendor_invoices/lib/sp_vendor_invoices.rb +12 -0
- data/vendor/vendor_orders/lib/sp_vendor_orders/api/vendor_orders_api.rb +323 -0
- data/vendor/vendor_orders/lib/sp_vendor_orders.rb +12 -0
- data/vendor/vendor_transaction_status/lib/sp_vendor_transaction_status/api/vendor_transaction_api.rb +75 -0
- data/vendor/vendor_transaction_status/lib/sp_vendor_transaction_status.rb +12 -0
- data/vendor/vendors_shipments/lib/sp_vendors_shipments/api/vendor_shipping_api.rb +337 -0
- data/vendor/vendors_shipments/lib/sp_vendors_shipments.rb +12 -0
- metadata +321 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0627464f44e6cbe35d99ea9405211a6aebf7d2276eea6532f886d9c96a33d1d8
|
|
4
|
+
data.tar.gz: 6dd7221be23aada8e99d15d247d33b6c22d3e96e0b21e974253e3dd9df89e29d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: defb167f4de77e60be1b1c21dfeab17017717e70117a3a3f41539296cc0cdbee17c5b3d449630b4df7b9c8cfec2433f6f1624de6840fc4dcad7f32092e82197e
|
|
7
|
+
data.tar.gz: c917ac15645bed83f5e5362eec43807b23e81acd4c4555c9ef3a12c1660d48c0d161aa89511035ccb5a1dcf8a8fa8f7280731500b064c9824829178789d1a333
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to this gem. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
|
|
6
|
+
Changes that only track updates to Amazon's API models are not
|
|
7
|
+
considered breaking and do not trigger a major version bump.
|
|
8
|
+
|
|
9
|
+
## [2.0.0] - 2026-09-03
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- The `AmazonSpClients::V2` namespace (`require 'amazon_sp_clients/v2'`):
|
|
14
|
+
a per-merchant `Client` with an explicit, frozen `Config` instead of
|
|
15
|
+
the thread-local global; a thread-safe token source (a callback, or
|
|
16
|
+
LWA refresh with one exchange per expiry); restricted data tokens as
|
|
17
|
+
an `rdt:` argument with per-resource caching; typed errors under
|
|
18
|
+
`V2::Error`; and one generated class per API module, for the same 14
|
|
19
|
+
modules. Responses are the same `ApiResponse`. The README has the
|
|
20
|
+
usage and the v1 to V2 migration table.
|
|
21
|
+
- Feed upload, feed result download and report download on the V2
|
|
22
|
+
client. Report documents come back gunzipped and UTF-8 tagged when
|
|
23
|
+
Amazon gzipped them.
|
|
24
|
+
- `RDT.report_document(id)`, the resource list for a restricted report
|
|
25
|
+
document, next to the `ORDERS` and `ORDERS_AND_ITEMS` presets.
|
|
26
|
+
- `rake yard:verify` and a CI job that fail when a public V2 object
|
|
27
|
+
has no doc comment.
|
|
28
|
+
- A second template set in the generator. Each `codegen-config.yml`
|
|
29
|
+
entry lists its template sets. Generation now refuses to run while
|
|
30
|
+
tracked generated files belong to no configured module, and fails on
|
|
31
|
+
names that Ruby or the V2 method signature already use.
|
|
32
|
+
- A release workflow. Pushing a `v*` tag publishes the gem to
|
|
33
|
+
rubygems.org through Trusted Publishing and opens a GitHub Release
|
|
34
|
+
with the CHANGELOG entry. `rake release` is disabled.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- The gem is named `sp_api_clients` on rubygems.org; the old name
|
|
39
|
+
started with a company name that is not ours. The `AmazonSpClients`
|
|
40
|
+
namespace and the `amazon_sp_clients/...` require paths are
|
|
41
|
+
unchanged, and `require 'sp_api_clients'` loads the v1 entry point.
|
|
42
|
+
A host that still installs `amazon_sp_clients` from git must drop
|
|
43
|
+
that line when it takes this gem: Bundler treats them as two gems,
|
|
44
|
+
and both ship the same files. The V2 default User-Agent names the
|
|
45
|
+
gem, so it changes too.
|
|
46
|
+
- The built gem ships only `lib/`, `vendor/`, the gemspec and the
|
|
47
|
+
top-level docs. Tests, the generator, CI config and dev tooling stay
|
|
48
|
+
out of it.
|
|
49
|
+
- The deprecated AWS IAM and logger settings stay as no-ops. They were
|
|
50
|
+
announced for removal in 2.0, but every consumer still sets them, so
|
|
51
|
+
they leave together with the v1 API in a later major.
|
|
52
|
+
- The Faraday requirement is unchanged (`>= 1.10, < 3`). The major
|
|
53
|
+
version marks the new namespace, not a dependency change. v1 is
|
|
54
|
+
unchanged.
|
|
55
|
+
|
|
56
|
+
## [1.9.0] - 2026-09-01
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- Faraday 2 support. The gem now runs on Faraday 1.10 and Faraday 2;
|
|
61
|
+
CI tests the suite against both majors on Ruby 3.3 and 3.4.
|
|
62
|
+
- A clear `LoadError` at boot when the bundle pairs Faraday 2 with
|
|
63
|
+
faraday-httpclient 1.x. A stale lock can produce this pair, since
|
|
64
|
+
that adapter gem has no runtime dependency on faraday. The message
|
|
65
|
+
names the `bundle update` command that fixes the lock.
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- The `faraday` dependency is `>= 1.10, < 3` (was `~> 1.4`).
|
|
70
|
+
- New dependencies `faraday-httpclient` and `faraday-retry`. Faraday 1
|
|
71
|
+
already ships both, so nothing changes there. Faraday 2 stopped
|
|
72
|
+
bundling them: the first provides the HTTPClient adapter the gem
|
|
73
|
+
uses, the second defines `Faraday::RetriableResponse`, which the
|
|
74
|
+
error middleware raises on HTTP 429 and consumers rescue for
|
|
75
|
+
throttling.
|
|
76
|
+
|
|
77
|
+
### Removed
|
|
78
|
+
|
|
79
|
+
- The unused `faraday_middleware` dependency. It pinned
|
|
80
|
+
`faraday ~> 1.0`, which blocked Faraday 2 in any bundle with this
|
|
81
|
+
gem.
|
|
82
|
+
- The `params` field in error payloads (`error.response[:request]`).
|
|
83
|
+
Real adapters never fill it, so it was always `nil`. Error classes
|
|
84
|
+
and messages are unchanged.
|
|
85
|
+
|
|
86
|
+
## [1.8.0] - 2026-09-01
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- Pure-Ruby code generator (`lib/generator`, `rake generate`). It
|
|
91
|
+
replaces swagger-codegen, so regeneration no longer needs Java. The
|
|
92
|
+
Amazon spec revision is pinned in `selling-partner-api-models.sha`;
|
|
93
|
+
CI verifies committed output matches regeneration at that pin, and a
|
|
94
|
+
nightly workflow opens a PR when Amazon updates the specs.
|
|
95
|
+
- CI on GitHub Actions: RSpec on Ruby 3.3 and 3.4, plus RuboCop.
|
|
96
|
+
- Characterization specs that pin the current public behavior of
|
|
97
|
+
`Configuration`, `Session`, `ApiClient`, `ApiResponse`,
|
|
98
|
+
`TokenExchangeAuth`, the `RaiseError` middleware, and the module
|
|
99
|
+
helpers (feed upload/download, report download).
|
|
100
|
+
- LICENSE (MIT) and this changelog.
|
|
101
|
+
|
|
102
|
+
### Changed
|
|
103
|
+
|
|
104
|
+
- Minimum Ruby version is 3.3 (was 2.3).
|
|
105
|
+
- Generated files were regenerated with the new generator. Same code,
|
|
106
|
+
new `Generated by:` header, and the unused commented-out model
|
|
107
|
+
requires are gone from the vendor entry files.
|
|
108
|
+
- `codegen-config.yml` now lists only the 14 API modules that have
|
|
109
|
+
consumers.
|
|
110
|
+
|
|
111
|
+
### Deprecated
|
|
112
|
+
|
|
113
|
+
- The AWS IAM configuration settings `access_key`, `secret_key`,
|
|
114
|
+
`role_arn`, and `credentials_provider`. Amazon dropped the SigV4
|
|
115
|
+
signing requirement in October 2023. The setters are accepted and
|
|
116
|
+
ignored; they go away together with the v1 API in a later major.
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- Grantless sessions re-authenticate after their token expires
|
|
121
|
+
(a typo'd variable made `refresh` a no-op for them).
|
|
122
|
+
- POST, PUT, and PATCH requests keep their query params. They were
|
|
123
|
+
silently dropped before, which broke 21 operations, including
|
|
124
|
+
`put_listings_item` and `patch_listings_item`.
|
|
125
|
+
- Per-operation header params (such as `Accept`) are sent.
|
|
126
|
+
- Raised errors no longer carry secrets: auth headers are filtered
|
|
127
|
+
from the exception payload, and the token service's request body
|
|
128
|
+
(client secret, refresh token) is filtered too.
|
|
129
|
+
- `config.endpoint = 'zz'` raises a clear `ArgumentError` instead of
|
|
130
|
+
`KeyError: key not found: nil`.
|
|
131
|
+
- A string-keyed response hash no longer turns `ApiResponse#payload`
|
|
132
|
+
into nil.
|
|
133
|
+
- `MARKETPLACE_IDS` includes Saudi Arabia (`sa`), matching
|
|
134
|
+
`MARKETPLACE_ENDPOINT_MAP`.
|
|
135
|
+
- `config.timeout` now applies to every connection (token exchange,
|
|
136
|
+
feed upload, report download). Only the API client honored it
|
|
137
|
+
before; the rest could hang forever.
|
|
138
|
+
|
|
139
|
+
### Removed
|
|
140
|
+
|
|
141
|
+
- AWS SigV4 request signing and the STS AssumeRole call, with the
|
|
142
|
+
`aws-sdk-core` and `aws-sigv4` dependencies. `new_session` no
|
|
143
|
+
longer makes a synchronous AWS network call, and
|
|
144
|
+
`Session#role_credentials` / `Session#credentials_provider` are
|
|
145
|
+
gone.
|
|
146
|
+
- The 17 vendored API modules with no consumers (catalog_items_2020,
|
|
147
|
+
catalog_items_v0, fba_inbound, fulfillment_inbound_v0,
|
|
148
|
+
merchant_fulfillment_v0, messaging, notifications, product_fees_v0,
|
|
149
|
+
product_pricing_v0, sales, sellers, services, shipping,
|
|
150
|
+
solicitations, uploads_2020, vdf_payments_v1, vdf_transactions_v1)
|
|
151
|
+
and their require shims.
|
|
152
|
+
- The generated per-module scaffolding under `vendor/`: models
|
|
153
|
+
(1,037 files nothing required), per-module api_client /
|
|
154
|
+
configuration / api_error / version copies, and gem boilerplate.
|
|
155
|
+
Each vendor module now holds only its entry file and API classes.
|
|
156
|
+
- Dead code: `ServiceError`, `Configuration#basic_auth_token`, the
|
|
157
|
+
inert `host=` writer, and typhoeus-era configuration attrs
|
|
158
|
+
(`verify_ssl`, `cert_file`, `params_encoding`, and friends).
|
|
159
|
+
- Travis CI config, `.ruby-gemset`, and the broken `.gitmodules`.
|
|
160
|
+
- The swagger-codegen mustache templates (`codegen-templates/`) and
|
|
161
|
+
the old `codegen:generate` / `codegen:clean` rake tasks.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2026 Dropstream
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# sp_api_clients
|
|
2
|
+
|
|
3
|
+
> **Status: experimental.** This gem is in the middle of large changes:
|
|
4
|
+
> a new code generator, a second client (`V2`), and consumers still
|
|
5
|
+
> moving over. Interfaces can change between releases. For a maintained,
|
|
6
|
+
> complete SP-API client we recommend
|
|
7
|
+
> [peddler](https://github.com/lineofflight/peddler).
|
|
8
|
+
|
|
9
|
+
The gem is `sp_api_clients`. The code keeps the `AmazonSpClients`
|
|
10
|
+
namespace and the `amazon_sp_clients/...` require paths. This project
|
|
11
|
+
is not affiliated with or endorsed by Amazon.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem 'sp_api_clients', '~> 2.0'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Releases are on [rubygems.org](https://rubygems.org/gems/sp_api_clients).
|
|
20
|
+
A git source (`gem 'sp_api_clients', git: ...`) still works, but it
|
|
21
|
+
follows a branch instead of a version. If you keep one, pin a `tag:`.
|
|
22
|
+
|
|
23
|
+
Either way this requires only the main (root) gem, but won't load any of
|
|
24
|
+
the generated SP APIs. The idea is to generate code for all APIs we may
|
|
25
|
+
need across our system, but allow requiring per project/repo basis.
|
|
26
|
+
Because of that, each API must be required explicitly:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
require 'amazon_sp_clients' # or 'sp_api_clients'; Bundler.require does this for you
|
|
30
|
+
|
|
31
|
+
# in active_cart
|
|
32
|
+
require 'amazon_sp_clients/sp_orders_v0' # Orders API
|
|
33
|
+
# ...and others
|
|
34
|
+
|
|
35
|
+
# in active_fulfillment
|
|
36
|
+
require 'amazon_sp_clients/sp_fba_inventory' # FBA Inventory API
|
|
37
|
+
# ...and others
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Generally the you should look for files with `sp_` prefix inside `lib` dir.
|
|
41
|
+
|
|
42
|
+
### Faraday
|
|
43
|
+
|
|
44
|
+
The gem works with Faraday 1.10 and Faraday 2; CI runs the suite
|
|
45
|
+
against both.
|
|
46
|
+
|
|
47
|
+
When you move an app from Faraday 1 to Faraday 2, run:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
bundle update faraday faraday-httpclient faraday-retry
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A plain `bundle install` after changing the `faraday` pin is not
|
|
54
|
+
enough. The lock keeps `faraday-httpclient` 1.x, which cannot load
|
|
55
|
+
under Faraday 2 (it has no runtime dependency on faraday, so nothing
|
|
56
|
+
forces the 2.x adapter). The gem detects this pair at boot and raises
|
|
57
|
+
a `LoadError` with the command above.
|
|
58
|
+
|
|
59
|
+
## Usage Example
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
require 'amazon_sp_clients/sp_orders_v0'
|
|
63
|
+
require 'dotenv/load'
|
|
64
|
+
|
|
65
|
+
AmazonSpClients.configure do |c|
|
|
66
|
+
c.client_id = ENV['AMZ_CLIENT_ID']
|
|
67
|
+
c.client_secret = ENV['AMZ_CLIENT_SECRET']
|
|
68
|
+
|
|
69
|
+
c.sandbox_env!
|
|
70
|
+
c.logger = Logger.new($stdout)
|
|
71
|
+
c.logger.level = Logger::DEBUG
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
session = AmazonSpClients.new_session(refresh_token)
|
|
75
|
+
|
|
76
|
+
orders_api = AmazonSpClients::SpOrdersV0::OrdersV0Api.new(session)
|
|
77
|
+
get_orders_response =
|
|
78
|
+
orders_api.get_orders(['ATVPDKIKX0DER'], created_after: 'TEST_CASE_200')
|
|
79
|
+
|
|
80
|
+
puts get_orders_response.payload # Hash with symbolized keys
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The AWS IAM settings (`access_key`, `secret_key`, `role_arn`,
|
|
84
|
+
`credentials_provider`) are deprecated. Amazon dropped the SigV4
|
|
85
|
+
signing requirement in October 2023, so the gem no longer signs
|
|
86
|
+
requests or calls STS. The setters still exist but do nothing. They
|
|
87
|
+
stay until the v1 API itself is removed in a later major.
|
|
88
|
+
|
|
89
|
+
### Restricted operations (requesting PII data)
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
orders_api = AmazonSpClients::SpOrdersV0::OrdersV0Api.new(session)
|
|
93
|
+
addr_resp =
|
|
94
|
+
orders_api.get_order_address('113-1435144-7135426', auth_names: [:pii])
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## V2 client
|
|
98
|
+
|
|
99
|
+
`AmazonSpClients::V2` is the second-generation client. It fixes the v1
|
|
100
|
+
design flaws: no global config, a thread-safe token source, restricted
|
|
101
|
+
data tokens as a plain argument, and typed errors. v1 stays in the gem,
|
|
102
|
+
so you can migrate one class at a time.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
require 'amazon_sp_clients/v2'
|
|
106
|
+
|
|
107
|
+
config = AmazonSpClients::V2::Config.new(
|
|
108
|
+
endpoint: 'na', # 'na', 'eu', 'fe' or a country code such as 'de'
|
|
109
|
+
sandbox: false,
|
|
110
|
+
timeout: 60, # read/write seconds; open_timeout: 10
|
|
111
|
+
client_id: nil, # LWA app credentials; only refresh-token clients and LWA need them
|
|
112
|
+
client_secret: nil
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# The block runs before every request and returns the current access token.
|
|
116
|
+
client = AmazonSpClients::V2::Client.new(config) { store.access_token }
|
|
117
|
+
|
|
118
|
+
# Or let the client exchange a refresh token itself (needs client_id and client_secret).
|
|
119
|
+
client = AmazonSpClients::V2::Client.with_refresh_token(config, refresh_token)
|
|
120
|
+
|
|
121
|
+
orders = client.orders_v0.get_orders(['ATVPDKIKX0DER'], created_after: '2026-09-01T00:00:00Z')
|
|
122
|
+
orders.payload[:Orders] # symbol keys, as in v1
|
|
123
|
+
orders.payload[:NextToken]
|
|
124
|
+
orders.reported_rate_limit # Float from x-amzn-RateLimit-Limit, or nil
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
To read a rotated refresh token back, build the credentials yourself
|
|
128
|
+
and keep the reference:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
lwa = AmazonSpClients::V2::LWA.new(config)
|
|
132
|
+
creds = AmazonSpClients::V2::Credentials::RefreshToken.new(lwa, refresh_token)
|
|
133
|
+
client = AmazonSpClients::V2::Client.new(config, credentials: creds)
|
|
134
|
+
creds.refresh_token # the latest one LWA returned; persist it when it changes
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
One client per merchant. It owns one connection and is safe to share
|
|
138
|
+
across threads. Required parameters are positional, in the same order
|
|
139
|
+
as v1; optional ones are keywords. Unknown keywords raise
|
|
140
|
+
`ArgumentError` (v1 ignored them), so pass only the parameters the
|
|
141
|
+
operation has.
|
|
142
|
+
|
|
143
|
+
### Restricted data tokens
|
|
144
|
+
|
|
145
|
+
Operations that return PII take `rdt:`, a list of restricted resources.
|
|
146
|
+
The client fetches the token, caches it until it expires, and sends it
|
|
147
|
+
instead of the access token.
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
rdt = AmazonSpClients::V2::RDT
|
|
151
|
+
client.orders_v0.get_orders(ids, created_after: since, rdt: rdt::ORDERS_AND_ITEMS)
|
|
152
|
+
client.reports_2021.get_report_document(doc_id, rdt: rdt.report_document(doc_id))
|
|
153
|
+
|
|
154
|
+
# Any other restricted resource: method, path template, PII fields wanted.
|
|
155
|
+
rdt.resource('GET', '/orders/v0/orders/{orderId}', %w[buyerInfo shippingAddress])
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Errors
|
|
159
|
+
|
|
160
|
+
Every failure is an `AmazonSpClients::V2::Error`. Match on the class
|
|
161
|
+
and on `code`, never on the message.
|
|
162
|
+
|
|
163
|
+
| Class | When |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `ThrottledError` | 429. Not a `ClientError`, so rescuing `ClientError` does not swallow it. |
|
|
166
|
+
| `UnauthorizedError`, `ForbiddenError` | 401, 403 |
|
|
167
|
+
| `NotFoundError` | 404 |
|
|
168
|
+
| `BadRequestError`, `ClientError` | 400, other 4xx. `code` holds the SP-API error code, e.g. `InvalidInput`. |
|
|
169
|
+
| `ServerError` | 5xx |
|
|
170
|
+
| `InvalidGrantError`, `InvalidClientError`, `AuthError` | LWA rejected the token request; `code` is `invalid_grant`, `invalid_client`, ... |
|
|
171
|
+
| `TimeoutError`, `ConnectionError` | no usable response; the original exception is `cause` |
|
|
172
|
+
| `ParseError` | a 2xx body that is not JSON |
|
|
173
|
+
| `DocumentError` | a presigned S3 upload or download failed |
|
|
174
|
+
|
|
175
|
+
Rescue subclasses before parents. Every error carries `status`,
|
|
176
|
+
`request_id`, `request` and `response`, with secrets redacted.
|
|
177
|
+
|
|
178
|
+
### Feed and report documents
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
client.upload_feed_document(feed_document_payload, 'text/xml; charset=UTF-8', body)
|
|
182
|
+
client.download_feed_result(feed_document_payload) # Hash with string keys
|
|
183
|
+
client.download_report_document(report_document_payload) # String, gunzipped when needed
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Migrating from v1
|
|
187
|
+
|
|
188
|
+
| v1 | V2 |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `AmazonSpClients.configure` block | `Config.new(endpoint: ...)`, one per merchant |
|
|
191
|
+
| `AmazonSpClients.new_callback_session { token }` | `Client.new(config) { token }` |
|
|
192
|
+
| `AmazonSpClients.new_session(refresh_token)` | `Client.with_refresh_token(config, refresh_token)` |
|
|
193
|
+
| `TokenExchangeAuth.new(refresh_token).exchange` | `LWA.new(config).exchange(refresh_token: refresh_token)`. The config must carry `client_id` and `client_secret`; `LWA.new` raises `ArgumentError` when they are missing, where v1 sent the request and got an LWA error back. |
|
|
194
|
+
| `response[:access_token]` | `token.access_token`, `token.expires_in`, `token.expires_at` |
|
|
195
|
+
| `SpOrdersV0::OrdersV0Api.new(session)` | `client.orders_v0` |
|
|
196
|
+
| `get_orders(ids, opts)` with an options Hash | `get_orders(ids, **opts)` with real parameter names only |
|
|
197
|
+
| `auth_names: [:orders_and_items]` | `rdt: RDT::ORDERS_AND_ITEMS` |
|
|
198
|
+
| `auth_names: [{ method: 'GET', path: path }]` | `rdt: RDT.report_document(doc_id)` for a report document, `rdt: [RDT.resource('GET', path)]` for anything else |
|
|
199
|
+
| `AmazonSpClients.configure.region` | `config.region` |
|
|
200
|
+
| `AmazonSpClients.configure.sandbox_env!` / `disable_sandbox!` | `Config.new(sandbox: true)`. The config is frozen, so a client cannot be switched after it is built. |
|
|
201
|
+
| `c.logger`, `c.role_arn`, `c.access_key`, `c.secret_key`, `c.credentials_provider` | nothing. v1 has ignored them since 1.8.0; delete the lines, and the AWS credential code that fed them. |
|
|
202
|
+
| the `Dropstream/1.0` user agent | `Config.new(user_agent: 'YourApp/1.0 ...')`. The default names this gem; Amazon asks for the application name. |
|
|
203
|
+
| `rescue Faraday::RetriableResponse` | `rescue V2::ThrottledError` |
|
|
204
|
+
| `rescue Faraday::ForbiddenError, Faraday::UnauthorizedError` | `rescue V2::ForbiddenError, V2::UnauthorizedError`. In v1 these also covered the token endpoint; in V2 those are `AuthError` (see the next row). |
|
|
205
|
+
| message starts with `Service 'token'` | `rescue V2::AuthError`, then `e.code`. A token-endpoint 4xx other than 429 is an `AuthError`, 401 and 403 included, so branch on `e.status` if you mapped those to an auth failure. The other three cases are not `AuthError`: 429 is a `ThrottledError`, 5xx is a `ServerError`, and a 200 with no `access_token` is a `ParseError`. |
|
|
206
|
+
| `rescue Faraday::ResourceNotFound` | `rescue V2::NotFoundError` |
|
|
207
|
+
| `rescue Faraday::BadRequestError, Faraday::ClientError` | `rescue V2::BadRequestError, V2::ClientError` |
|
|
208
|
+
| `rescue Faraday::ServerError` | `rescue V2::ServerError, V2::TimeoutError`. Faraday makes a timeout a `ServerError`; V2 makes it a `ConnectionError`, so add it where you treated 5xx as worth retrying. |
|
|
209
|
+
| `Faraday::ConnectionFailed`, `Faraday::SSLError` reaching your last `rescue` | `rescue V2::ConnectionError`. v1 let them fall through untyped; V2 wraps every transport failure, `TimeoutError` included, with the original exception as `cause`. |
|
|
210
|
+
| `e.message =~ /Please try again/` and other text matches | Match on the class and on `code`. The text changed: `"<status> <code>: <message> (<details>)"` for SP-API, `"<status> <code>: <description>"` for LWA, `"<status> (no body)"` and friends when there is nothing to show. The wording is not a contract. |
|
|
211
|
+
| `order_statuses: []` in the options Hash | The same on the wire: `[]` is sent as an empty value (`OrderStatuses=`), a nil keyword is left off. |
|
|
212
|
+
| message matches `InvalidInput` | `e.code == 'InvalidInput'` |
|
|
213
|
+
| `upload_feed_data`, `download_feed_report`, `download_report_document` | `client.upload_feed_document`, `client.download_feed_result`, `client.download_report_document`. The last one gunzips for you. The first returns nil; v1 returned the S3 response, which nothing read. |
|
|
214
|
+
|
|
215
|
+
## Code generation
|
|
216
|
+
|
|
217
|
+
The v1 API classes under `vendor/` and the V2 classes under
|
|
218
|
+
`lib/amazon_sp_clients/v2/apis/` are generated by `lib/generator` (plain
|
|
219
|
+
Ruby + ERB, no external tools) from Amazon's official
|
|
220
|
+
[selling-partner-api-models](https://github.com/amzn/selling-partner-api-models)
|
|
221
|
+
specs. The generator clones that repo into `amzn-models/` (gitignored)
|
|
222
|
+
and checks out the exact revision pinned in
|
|
223
|
+
`selling-partner-api-models.sha`, so generation is reproducible.
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
bundle exec rake generate # regenerate at the pinned revision
|
|
227
|
+
bundle exec rake generate:setup # only clone/sync the spec repo
|
|
228
|
+
bundle exec rake generate:verify # regenerate and fail on any drift (runs in CI)
|
|
229
|
+
bundle exec rake generate:update # pull latest specs, regenerate, advance the pin
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Which APIs get generated, and with which template sets (`v1`, `v2`), is
|
|
233
|
+
controlled by `codegen-config.yml`. To adopt newer Amazon specs, run
|
|
234
|
+
`rake generate:update` and review the diff — the pin file change plus
|
|
235
|
+
the regenerated files — in its own PR.
|
|
236
|
+
|
|
237
|
+
`bundle exec rake yard:verify` fails when a public V2 object has no doc
|
|
238
|
+
comment; CI runs it.
|
|
239
|
+
|
|
240
|
+
Generated files carry a `Generated by: lib/generator` header. Never edit
|
|
241
|
+
them by hand; change the generator (or the templates in
|
|
242
|
+
`lib/generator/templates/`) and regenerate.
|
|
243
|
+
|
|
244
|
+
## Releasing
|
|
245
|
+
|
|
246
|
+
A release is a version tag. Nothing else publishes. The `Release`
|
|
247
|
+
workflow (`.github/workflows/release.yml`) checks the tag against the
|
|
248
|
+
version, runs the suite, builds the gem, pushes it to rubygems.org and
|
|
249
|
+
opens a GitHub Release with the CHANGELOG entry.
|
|
250
|
+
|
|
251
|
+
The push uses rubygems.org's Trusted Publishing: the job's GitHub OIDC
|
|
252
|
+
token is exchanged for a short-lived key, so no API key is stored
|
|
253
|
+
anywhere. rubygems.org has to trust this repository's workflow first.
|
|
254
|
+
Before the first release, sign in to rubygems.org, open the Trusted
|
|
255
|
+
publishers page of your profile and add a pending publisher: gem
|
|
256
|
+
`sp_api_clients`, repository owner `dropstream`, repository
|
|
257
|
+
`amazon_sp_clients` (the repository keeps its old name), workflow
|
|
258
|
+
`release.yml`, environment empty. A
|
|
259
|
+
pending publisher expires when the first push does not follow soon
|
|
260
|
+
(12 hours at the time of writing). After the first release the
|
|
261
|
+
publisher belongs to the gem and stays.
|
|
262
|
+
|
|
263
|
+
1. Set `AmazonSpClients::VERSION` in `lib/amazon_sp_clients/version.rb`.
|
|
264
|
+
2. Re-lock all three lockfiles, or CI's frozen install fails:
|
|
265
|
+
|
|
266
|
+
```sh
|
|
267
|
+
bundle lock --local
|
|
268
|
+
BUNDLE_GEMFILE=gemfiles/faraday_1.gemfile bundle lock --local
|
|
269
|
+
BUNDLE_GEMFILE=gemfiles/faraday_2.gemfile bundle lock --local
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
3. Give the CHANGELOG entry its release date: `## [X.Y.Z] - YYYY-MM-DD`.
|
|
273
|
+
The workflow stops when the version has no entry.
|
|
274
|
+
4. Commit, then push an annotated tag on that commit:
|
|
275
|
+
|
|
276
|
+
```sh
|
|
277
|
+
git tag -a vX.Y.Z -m 'vX.Y.Z'
|
|
278
|
+
git push origin vX.Y.Z
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The tag must be `v` plus the version, or the workflow stops before it
|
|
282
|
+
builds. rubygems.org rejects a version it already has, so a failed
|
|
283
|
+
release needs a new version and a new tag, not a re-run. `rake release`
|
|
284
|
+
is disabled; it would tag and push from a laptop.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
|
|
5
|
+
module AmazonSpClients
|
|
6
|
+
# Loads the HTTPClient Faraday adapter (Faraday 2 no longer auto-loads
|
|
7
|
+
# adapter gems; a no-op under Faraday 1).
|
|
8
|
+
#
|
|
9
|
+
# Bundler can pair Faraday 2 with faraday-httpclient 1.x — that adapter
|
|
10
|
+
# gem has no runtime dependency on faraday, so a stale lock entry
|
|
11
|
+
# survives a `bundle update faraday`. The pair fails at require time
|
|
12
|
+
# with a cryptic NoMethodError; turn it into a message that names the
|
|
13
|
+
# fix.
|
|
14
|
+
module AdapterLoader
|
|
15
|
+
FIX_CMD = 'bundle update faraday faraday-httpclient faraday-retry'
|
|
16
|
+
|
|
17
|
+
def self.require_adapter!
|
|
18
|
+
require 'faraday/httpclient'
|
|
19
|
+
rescue NoMethodError
|
|
20
|
+
version = Gem.loaded_specs['faraday-httpclient']&.version
|
|
21
|
+
raise LoadError,
|
|
22
|
+
"faraday-httpclient #{version} cannot load under " \
|
|
23
|
+
"Faraday #{Faraday::VERSION}. Run: #{FIX_CMD}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
AmazonSpClients::AdapterLoader.require_adapter!
|