fulfil_api 0.4.1 → 0.5.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 +4 -4
- data/README.md +41 -0
- data/lib/fulfil_api/configuration.rb +1 -1
- data/lib/fulfil_api/test_helper.rb +41 -0
- data/lib/fulfil_api/tpl_client.rb +146 -0
- data/lib/fulfil_api/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22b6b63d1460a3a0d6b6c5ef3b33b018291d6919a27c32664c7649922a930852
|
|
4
|
+
data.tar.gz: 0a87ce490bca0026c5764ded0e887a3cdffd4cf0d9a3f13bcfd8e5a5a888cb43
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dedeecd3042e63045c2a5215d5bc6121c99a0863a65db953657cef068ff75f060271533d8ce2dd39a9b24ca94834b5b0b1282778ba6f0fb8d18efd419ecdff32
|
|
7
|
+
data.tar.gz: b39a10b911e3c9909cb7f21bfdf4cde91db64438eb6060a54700e4596ec4fe32961b691e49f4370211fdca0f8b343b0c63421ccfeb6d5959b6c05524ba415a94
|
data/README.md
CHANGED
|
@@ -127,6 +127,47 @@ line_items = FulfilApi::Resource.set(model_name: "sale.line").where(["id", "in",
|
|
|
127
127
|
line_items = FulfilApi::Resource.set(model_name: "sale.line").find_by(["sale.id", "=", 100])
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
### Using the 3PL (TPL) Client
|
|
131
|
+
|
|
132
|
+
The gem also includes a client for Fulfil's [3PL Integration API](https://fulfil-3pl-integration-api.readme.io/reference/getting-started-with-your-api). This is a separate API that allows third-party logistics providers to interact with Fulfil on behalf of a merchant.
|
|
133
|
+
|
|
134
|
+
#### Configuration
|
|
135
|
+
|
|
136
|
+
Configure the 3PL client through the `tpl` option in the configuration block:
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
FulfilApi.configure do |config|
|
|
140
|
+
config.merchant_id = "the-id-of-the-merchant"
|
|
141
|
+
|
|
142
|
+
config.tpl = {
|
|
143
|
+
auth_token: ENV["FULFIL_3PL_AUTH_TOKEN"], # required
|
|
144
|
+
merchant_id: "a-different-merchant-id", # optional, falls back to config.merchant_id
|
|
145
|
+
api_version: "v1" # optional, defaults to "v1"
|
|
146
|
+
}
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Making Requests
|
|
151
|
+
|
|
152
|
+
The 3PL client is accessible via `FulfilApi.tpl_client` and supports the standard HTTP methods:
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
# GET request with optional URL parameters
|
|
156
|
+
FulfilApi.tpl_client.get("inbound-transfers", url_parameters: { page: 1, per_page: 25 })
|
|
157
|
+
|
|
158
|
+
# POST request with a request body
|
|
159
|
+
FulfilApi.tpl_client.post("inbound-transfers/receive.json", body: { tracking_number: "ABC123" })
|
|
160
|
+
|
|
161
|
+
# PUT request with a request body
|
|
162
|
+
FulfilApi.tpl_client.put("inbound-transfers/receive.json", body: { status: "received" })
|
|
163
|
+
|
|
164
|
+
# PATCH request with a request body
|
|
165
|
+
FulfilApi.tpl_client.patch("inbound-transfers/receive.json", body: { status: "received" })
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
> **NOTE:** For the full list of available 3PL API endpoints, refer to the [Fulfil 3PL Integration API documentation](https://fulfil-3pl-integration-api.readme.io/reference/getting-started-with-your-api).
|
|
170
|
+
|
|
130
171
|
## Development
|
|
131
172
|
|
|
132
173
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -6,7 +6,7 @@ module FulfilApi
|
|
|
6
6
|
# This model holds configuration settings and provides thread-safe access
|
|
7
7
|
# to these settings.
|
|
8
8
|
class Configuration
|
|
9
|
-
attr_accessor :access_token, :api_version, :merchant_id, :request_options
|
|
9
|
+
attr_accessor :access_token, :api_version, :merchant_id, :request_options, :tpl
|
|
10
10
|
|
|
11
11
|
DEFAULT_API_VERSION = "v2"
|
|
12
12
|
DEFAULT_REQUEST_OPTIONS = { open_timeout: 1, read_timeout: 5, write_timeout: 5, timeout: 5 }.freeze
|
|
@@ -41,8 +41,49 @@ module FulfilApi
|
|
|
41
41
|
.and_return(status: status, body: response.to_json, headers: { "Content-Type": "application/json" })
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# Stubs an HTTP request to the Fulfil 3PL API based on the provided parameters.
|
|
45
|
+
#
|
|
46
|
+
# @param [String, Symbol] method The HTTP method to be stubbed (e.g., :get, :post).
|
|
47
|
+
# @param [Hash] response The response body to return as a JSON object (default is {}).
|
|
48
|
+
# @param [Integer] status The HTTP status code to return (default is 200).
|
|
49
|
+
# @param [Hash] options Additional options for the request URL.
|
|
50
|
+
# @option options [String] :path The relative path to the 3PL endpoint
|
|
51
|
+
# (e.g., 'inbound-transfers/receive.json').
|
|
52
|
+
#
|
|
53
|
+
# @return [WebMock::RequestStub] The WebMock request stub object.
|
|
54
|
+
#
|
|
55
|
+
# @example Stub a GET request for the inbound transfers endpoint
|
|
56
|
+
# stub_fulfil_tpl_request(:get, path: "inbound-transfers", response: [{ id: 1 }])
|
|
57
|
+
#
|
|
58
|
+
# @example Stub a POST request for receiving an inbound transfer
|
|
59
|
+
# stub_fulfil_tpl_request(:post, path: "inbound-transfers/receive.json", response: { id: 123 })
|
|
60
|
+
#
|
|
61
|
+
# @example Stub all 3PL requests for a given method
|
|
62
|
+
# stub_fulfil_tpl_request(:get)
|
|
63
|
+
def stub_fulfil_tpl_request(method, response: {}, status: 200, **options)
|
|
64
|
+
stubbed_tpl_request_for(method, **options)
|
|
65
|
+
.and_return(status: status, body: response.to_json, headers: { "Content-Type": "application/json" })
|
|
66
|
+
end
|
|
67
|
+
|
|
44
68
|
private
|
|
45
69
|
|
|
70
|
+
# Builds the WebMock request stub for the Fulfil 3PL API based on the provided method and options.
|
|
71
|
+
#
|
|
72
|
+
# @param [String, Symbol] method The HTTP method to be stubbed (e.g., :get, :post).
|
|
73
|
+
# @param [Hash] options Additional options for the request URL.
|
|
74
|
+
# @option options [String] :path The relative path to the 3PL endpoint
|
|
75
|
+
# (e.g., 'inbound-transfers/receive.json').
|
|
76
|
+
#
|
|
77
|
+
# @return [WebMock::RequestStub] The WebMock request stub object.
|
|
78
|
+
def stubbed_tpl_request_for(method, **options)
|
|
79
|
+
case options.transform_keys(&:to_sym)
|
|
80
|
+
in { path: }
|
|
81
|
+
stub_request(method.to_sym, %r{fulfil.io/services/3pl/v\d+/#{path}(.*)}i)
|
|
82
|
+
else
|
|
83
|
+
stub_request(method.to_sym, %r{fulfil.io/services/3pl/v\d+}i)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
46
87
|
# Builds the WebMock request stub for the Fulfil API based on the provided method and options.
|
|
47
88
|
#
|
|
48
89
|
# @param [String, Symbol] method The HTTP method to be stubbed (e.g., :get, :post).
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "faraday/net_http_persistent"
|
|
5
|
+
|
|
6
|
+
module FulfilApi
|
|
7
|
+
# The {FulfilApi::TplClient} allows making proxy requests to Fulfil's 3PL
|
|
8
|
+
# carrier API endpoint. It provides a simple interface for interacting with
|
|
9
|
+
# the 3PL supplier API using standard HTTP methods.
|
|
10
|
+
#
|
|
11
|
+
# @example Using the TPL client
|
|
12
|
+
# FulfilApi.tpl_client.get("inbound-transfers", url_parameters: { page: 1 })
|
|
13
|
+
# FulfilApi.tpl_client.post("inbound-transfers/receive.json", body: { tracking_number: "123" })
|
|
14
|
+
class TplClient
|
|
15
|
+
class ConfigurationError < FulfilApi::Error; end
|
|
16
|
+
|
|
17
|
+
DEFAULT_API_VERSION = "v1"
|
|
18
|
+
|
|
19
|
+
# @param configuration [FulfilApi::Configuration]
|
|
20
|
+
def initialize(configuration)
|
|
21
|
+
@configuration = configuration
|
|
22
|
+
|
|
23
|
+
tpl_config = configuration.tpl || {}
|
|
24
|
+
|
|
25
|
+
@auth_token = tpl_config[:auth_token].presence ||
|
|
26
|
+
raise(ConfigurationError,
|
|
27
|
+
"Please provide a 3PL authentication token via config.tpl = { auth_token: ... }")
|
|
28
|
+
@merchant_id = tpl_config[:merchant_id].presence || configuration.merchant_id.presence ||
|
|
29
|
+
raise(ConfigurationError, "Please provide a merchant ID")
|
|
30
|
+
@api_version = tpl_config[:api_version].presence || DEFAULT_API_VERSION
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Performs an HTTP GET request to a 3PL API endpoint.
|
|
34
|
+
#
|
|
35
|
+
# @param relative_path [String] The relative path to the endpoint.
|
|
36
|
+
# @param url_parameters [Hash, nil] The optional URL parameters for the API endpoint.
|
|
37
|
+
# @return [Array, Hash, String] The parsed response body.
|
|
38
|
+
def get(relative_path, url_parameters: nil)
|
|
39
|
+
request(:get, relative_path, url_parameters)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Performs an HTTP PATCH request to a 3PL API endpoint.
|
|
43
|
+
#
|
|
44
|
+
# @param relative_path [String] The relative path to the endpoint.
|
|
45
|
+
# @param body [Array, Hash, nil] The request body for the PATCH HTTP request.
|
|
46
|
+
# @return [Array, Hash, String] The parsed response body.
|
|
47
|
+
def patch(relative_path, body: {})
|
|
48
|
+
request(:patch, relative_path, body)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Performs an HTTP POST request to a 3PL API endpoint.
|
|
52
|
+
#
|
|
53
|
+
# @param relative_path [String] The relative path to the endpoint.
|
|
54
|
+
# @param body [Array, Hash, nil] The request body for the POST HTTP request.
|
|
55
|
+
# @return [Array, Hash, String] The parsed response body.
|
|
56
|
+
def post(relative_path, body: {})
|
|
57
|
+
request(:post, relative_path, body)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Performs an HTTP PUT request to a 3PL API endpoint.
|
|
61
|
+
#
|
|
62
|
+
# @param relative_path [String] The relative path to the endpoint.
|
|
63
|
+
# @param body [Array, Hash, nil] The optional request body for the PUT HTTP request.
|
|
64
|
+
# @return [Array, Hash, String] The parsed response body.
|
|
65
|
+
def put(relative_path, body: nil)
|
|
66
|
+
return request(:put, relative_path) if body.nil?
|
|
67
|
+
|
|
68
|
+
request(:put, relative_path, body)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
attr_reader :api_version, :auth_token, :configuration, :merchant_id
|
|
74
|
+
|
|
75
|
+
# @return [String] The absolute URL to the API base URL.
|
|
76
|
+
def api_endpoint
|
|
77
|
+
@api_endpoint ||= "https://#{merchant_id}.fulfil.io"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Faraday::Connection]
|
|
81
|
+
def connection
|
|
82
|
+
@connection ||= Faraday.new(
|
|
83
|
+
headers: request_headers,
|
|
84
|
+
url: api_endpoint,
|
|
85
|
+
request: configuration.request_options
|
|
86
|
+
) do |connection|
|
|
87
|
+
connection.adapter :net_http_persistent
|
|
88
|
+
|
|
89
|
+
# Configuration of the request middleware
|
|
90
|
+
connection.request :json
|
|
91
|
+
|
|
92
|
+
# Configuration of the response middleware
|
|
93
|
+
connection.response :json
|
|
94
|
+
connection.response :raise_error
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @param relative_path [String] The relative path to the API endpoint.
|
|
99
|
+
# @return [String] The absolute path for the request to the API endpoint.
|
|
100
|
+
def expand_relative_path(relative_path)
|
|
101
|
+
path = relative_path.start_with?("/") ? relative_path[1..] : relative_path
|
|
102
|
+
"/services/3pl/#{api_version}/#{path}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @param exception [Faraday::Error] Any error raised by Faraday during the execution
|
|
106
|
+
# of the HTTP request to the API endpoint.
|
|
107
|
+
def handle_request_error(exception)
|
|
108
|
+
raise FulfilApi::Error.new(
|
|
109
|
+
exception.message,
|
|
110
|
+
details: {
|
|
111
|
+
response_body: exception.response_body,
|
|
112
|
+
response_headers: exception.response_headers,
|
|
113
|
+
response_status: exception.response_status
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @param method [Symbol, String] The HTTP verb for the HTTP request.
|
|
119
|
+
# @param relative_path [String] The relative path to the API endpoint.
|
|
120
|
+
# @return [Array, Hash, String] The parsed response body.
|
|
121
|
+
def request(method, relative_path, *args, **kwargs)
|
|
122
|
+
connection.send(method.to_sym, expand_relative_path(relative_path), *args, **kwargs).body
|
|
123
|
+
rescue Faraday::Error => e
|
|
124
|
+
handle_request_error(e)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# @return [Hash] The HTTP headers for any HTTP request to the 3PL API.
|
|
128
|
+
def request_headers
|
|
129
|
+
{
|
|
130
|
+
"Authorization" => "Bearer #{auth_token}",
|
|
131
|
+
"Content-Type" => "application/json"
|
|
132
|
+
}
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Builds an HTTP client to interact with Fulfil's 3PL API endpoint.
|
|
137
|
+
#
|
|
138
|
+
# @example
|
|
139
|
+
# FulfilApi.tpl_client.get("inbound-transfers")
|
|
140
|
+
# FulfilApi.tpl_client.post("inbound-transfers/receive.json", body: { tracking_number: "123" })
|
|
141
|
+
#
|
|
142
|
+
# @return [FulfilApi::TplClient]
|
|
143
|
+
def self.tpl_client
|
|
144
|
+
TplClient.new(FulfilApi.configuration)
|
|
145
|
+
end
|
|
146
|
+
end
|
data/lib/fulfil_api/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fulfil_api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stefan Vermaas
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -100,6 +100,7 @@ files:
|
|
|
100
100
|
- lib/fulfil_api/resource/persistable.rb
|
|
101
101
|
- lib/fulfil_api/resource/serializable.rb
|
|
102
102
|
- lib/fulfil_api/test_helper.rb
|
|
103
|
+
- lib/fulfil_api/tpl_client.rb
|
|
103
104
|
- lib/fulfil_api/version.rb
|
|
104
105
|
- sig/fulfil_api.rbs
|
|
105
106
|
homepage: https://www.github.com/codeturebv/fulfil_api
|