mailchimp-rest-api 0.2.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 +4 -4
- data/README.md +198 -156
- data/VERSION +1 -1
- data/lib/mailchimp-api/batch_request.rb +20 -3
- data/lib/mailchimp-api/client/api_methods.rb +37 -3
- data/lib/mailchimp-api/client/batch_methods.rb +63 -4
- data/lib/mailchimp-api/client.rb +60 -3
- data/lib/mailchimp-api/config.rb +18 -12
- data/lib/mailchimp-api/error.rb +35 -22
- data/lib/mailchimp-api/failed_request_error_builder.rb +11 -11
- data/lib/mailchimp-api/network_error_builder.rb +8 -11
- data/lib/mailchimp-api/pagination/list_each_item_helper.rb +37 -0
- data/lib/mailchimp-api/pagination/prepare_query_params.rb +51 -0
- data/lib/mailchimp-api/request.rb +40 -2
- data/lib/mailchimp-api/request_executor.rb +18 -4
- data/lib/mailchimp-api/resource.rb +2 -0
- data/lib/mailchimp-api/resources/audience/interest_categories.rb +69 -0
- data/lib/mailchimp-api/resources/audience/interests.rb +72 -0
- data/lib/mailchimp-api/resources/audience/member_tags.rb +45 -2
- data/lib/mailchimp-api/resources/audience/members.rb +98 -2
- data/lib/mailchimp-api/resources/audience/segment_members.rb +78 -0
- data/lib/mailchimp-api/resources/audience/segments.rb +125 -0
- data/lib/mailchimp-api/resources/audience/utils/subscriber_hash.rb +9 -0
- data/lib/mailchimp-api/resources/audience/webhooks.rb +69 -0
- data/lib/mailchimp-api/response.rb +30 -13
- data/lib/mailchimp-api/uri_builder.rb +13 -0
- data/lib/mailchimp-api.rb +141 -31
- metadata +12 -7
- data/lib/mailchimp-api/client/pagination_methods.rb +0 -51
data/lib/mailchimp-api/client.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MailchimpAPI
|
4
|
+
# Client class for interacting with the Mailchimp REST API
|
5
|
+
# @api public
|
4
6
|
class Client
|
7
|
+
# Current API version
|
5
8
|
API_VERSION = MailchimpAPI::API_VERSION
|
6
9
|
|
7
10
|
include APIMethods
|
8
11
|
include BatchMethods
|
9
|
-
include PaginationMethods
|
10
|
-
|
11
|
-
attr_reader :api_key, :api_url, :api_version, :authorization_token, :config
|
12
12
|
|
13
|
+
# Initializes a new Mailchimp API client
|
14
|
+
# @param api_key [String] Mailchimp API key in format <token>-<dc>
|
15
|
+
# @param http_opts [Hash] Optional HTTP client configuration
|
16
|
+
# @param retries [Integer] Number of retries for failed requests
|
17
|
+
# @raise [ArgumentError] if api_key is invalid
|
18
|
+
# @example
|
19
|
+
# client = MailchimpAPI::Client.new(api_key: "your-api-key-here")
|
13
20
|
def initialize(api_key:, http_opts: nil, retries: nil)
|
14
21
|
raise ArgumentError, "Invalid api_key" unless /\w+-\w+/.match?(api_key) # <token>-<dc>
|
15
22
|
dc = api_key.split("-", 2).last # initial api_key must have format
|
@@ -20,28 +27,78 @@ module MailchimpAPI
|
|
20
27
|
@config = Config.new(http_opts: http_opts, retries: retries)
|
21
28
|
end
|
22
29
|
|
30
|
+
# Sends a POST request to the Mailchimp API
|
31
|
+
# @param path [String] API endpoint path
|
32
|
+
# @param query [Hash] Optional query parameters
|
33
|
+
# @param body [Hash] Optional request body
|
34
|
+
# @param headers [Hash] Optional request headers
|
35
|
+
# @return [Response] API response
|
36
|
+
# @example
|
37
|
+
# client.post("/lists", body: { name: "New List" })
|
23
38
|
def post(path, query: nil, body: nil, headers: nil)
|
24
39
|
execute(Net::HTTP::Post, path, query: query, body: body, headers: headers)
|
25
40
|
end
|
26
41
|
|
42
|
+
# Sends a GET request to the Mailchimp API
|
43
|
+
# @param path [String] API endpoint path
|
44
|
+
# @param query [Hash] Optional query parameters
|
45
|
+
# @param body [Hash] Optional request body
|
46
|
+
# @param headers [Hash] Optional request headers
|
47
|
+
# @return [Response] API response
|
48
|
+
# @example
|
49
|
+
# client.get("/lists")
|
27
50
|
def get(path, query: nil, body: nil, headers: nil)
|
28
51
|
execute(Net::HTTP::Get, path, query: query, body: body, headers: headers)
|
29
52
|
end
|
30
53
|
|
54
|
+
# Sends a PATCH request to the Mailchimp API
|
55
|
+
# @param path [String] API endpoint path
|
56
|
+
# @param query [Hash] Optional query parameters
|
57
|
+
# @param body [Hash] Optional request body
|
58
|
+
# @param headers [Hash] Optional request headers
|
59
|
+
# @return [Response] API response
|
60
|
+
# @example
|
61
|
+
# client.patch("/lists/123", body: { name: "Updated List" })
|
31
62
|
def patch(path, query: nil, body: nil, headers: nil)
|
32
63
|
execute(Net::HTTP::Patch, path, query: query, body: body, headers: headers)
|
33
64
|
end
|
34
65
|
|
66
|
+
# Sends a PUT request to the Mailchimp API
|
67
|
+
# @param path [String] API endpoint path
|
68
|
+
# @param query [Hash] Optional query parameters
|
69
|
+
# @param body [Hash] Optional request body
|
70
|
+
# @param headers [Hash] Optional request headers
|
71
|
+
# @return [Response] API response
|
72
|
+
# @example
|
73
|
+
# client.put("/lists/123", body: { name: "Updated List" })
|
35
74
|
def put(path, query: nil, body: nil, headers: nil)
|
36
75
|
execute(Net::HTTP::Put, path, query: query, body: body, headers: headers)
|
37
76
|
end
|
38
77
|
|
78
|
+
# Sends a DELETE request to the Mailchimp API
|
79
|
+
# @param path [String] API endpoint path
|
80
|
+
# @param query [Hash] Optional query parameters
|
81
|
+
# @param body [Hash] Optional request body
|
82
|
+
# @param headers [Hash] Optional request headers
|
83
|
+
# @return [Response] API response
|
84
|
+
# @example
|
85
|
+
# client.delete("/lists/123")
|
39
86
|
def delete(path, query: nil, body: nil, headers: nil)
|
40
87
|
execute(Net::HTTP::Delete, path, query: query, body: body, headers: headers)
|
41
88
|
end
|
42
89
|
|
43
90
|
private
|
44
91
|
|
92
|
+
attr_reader :api_key
|
93
|
+
|
94
|
+
attr_reader :api_url
|
95
|
+
|
96
|
+
attr_reader :api_version
|
97
|
+
|
98
|
+
attr_reader :authorization_token
|
99
|
+
|
100
|
+
attr_reader :config
|
101
|
+
|
45
102
|
def execute(http_method, path, query:, body:, headers:)
|
46
103
|
headers = {"authorization" => authorization_token}.merge!(headers || {})
|
47
104
|
request = new_request(http_method, path: path, query: query, body: body, headers: headers)
|
data/lib/mailchimp-api/config.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MailchimpAPI
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# Internal class for storing and managing client configuration
|
5
|
+
# @api private
|
7
6
|
class Config
|
8
|
-
# Default
|
7
|
+
# Default configuration options
|
8
|
+
# @return [Hash] Frozen hash containing default settings
|
9
9
|
DEFAULTS = {
|
10
10
|
http_opts: {}.freeze,
|
11
11
|
retries: {enabled: true, count: 4, sleep: [0, 0.25, 0.75, 1.5].freeze}.freeze
|
12
12
|
}.freeze
|
13
13
|
|
14
|
-
|
14
|
+
# @return [Hash] HTTP client configuration options
|
15
|
+
attr_reader :http_opts
|
15
16
|
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# @
|
22
|
-
#
|
17
|
+
# @return [Hash] Retry configuration options
|
18
|
+
attr_reader :retries
|
19
|
+
|
20
|
+
# Creates a new configuration instance
|
21
|
+
# @param http_opts [Hash] Net::Http options for all requests
|
22
|
+
# @param retries [Hash] Retry configuration options
|
23
|
+
# @return [Config] Frozen configuration instance
|
24
|
+
# @example
|
25
|
+
# config = MailchimpAPI::Config.new(
|
26
|
+
# http_opts: { read_timeout: 30 },
|
27
|
+
# retries: { count: 3 }
|
28
|
+
# )
|
23
29
|
def initialize(http_opts: nil, retries: {})
|
24
30
|
@http_opts = http_opts.dup.freeze || DEFAULTS[:http_opts]
|
25
31
|
@retries = DEFAULTS[:retries].merge(retries || {}).freeze
|
data/lib/mailchimp-api/error.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MailchimpAPI
|
4
|
-
#
|
5
|
-
# Common interface for all errors
|
6
|
-
#
|
4
|
+
# Base error class for all Mailchimp API errors
|
7
5
|
class Error < StandardError
|
8
6
|
# @return [Response, nil] Returned response with non-200 status code
|
9
7
|
attr_reader :response
|
@@ -30,14 +28,21 @@ module MailchimpAPI
|
|
30
28
|
attr_reader :error_fields
|
31
29
|
end
|
32
30
|
|
33
|
-
#
|
34
|
-
# Namespace for specific MailchimpAPI errors
|
35
|
-
#
|
31
|
+
# Namespace for specific Mailchimp API errors
|
36
32
|
module Errors
|
37
|
-
#
|
38
33
|
# Raised when Mailchimp responds with any status code except 200, 201, 202, 204
|
39
|
-
#
|
40
34
|
class FailedRequest < Error
|
35
|
+
# Initializes a new FailedRequest error
|
36
|
+
# @param message [String, nil] Error message
|
37
|
+
# @param request [Request] The request that failed
|
38
|
+
# @param response [Response] The response received from Mailchimp
|
39
|
+
# @example
|
40
|
+
# begin
|
41
|
+
# client.get("/lists/123")
|
42
|
+
# rescue MailchimpAPI::Errors::FailedRequest => e
|
43
|
+
# puts e.error_title # => "Resource Not Found"
|
44
|
+
# puts e.error_detail # => "The requested resource could not be found."
|
45
|
+
# end
|
41
46
|
def initialize(message = nil, request:, response:)
|
42
47
|
@request = request
|
43
48
|
@response = response
|
@@ -56,11 +61,19 @@ module MailchimpAPI
|
|
56
61
|
end
|
57
62
|
end
|
58
63
|
|
59
|
-
#
|
60
|
-
# Raised when a network raised when executing the request
|
61
|
-
# List of network errors can be found in errors/network_error_builder.rb
|
62
|
-
#
|
64
|
+
# Raised when a network error occurs while executing the request
|
63
65
|
class NetworkError < Error
|
66
|
+
# Initializes a new NetworkError
|
67
|
+
# @param message [String, nil] Error message
|
68
|
+
# @param request [Request] The request that failed
|
69
|
+
# @param error [Exception] The original network error
|
70
|
+
# @example
|
71
|
+
# begin
|
72
|
+
# client.get("/lists")
|
73
|
+
# rescue MailchimpAPI::Errors::NetworkError => e
|
74
|
+
# puts e.error_title # => "Net::OpenTimeout"
|
75
|
+
# puts e.error_detail # => "execution expired"
|
76
|
+
# end
|
64
77
|
def initialize(message = nil, request:, error:)
|
65
78
|
super(message)
|
66
79
|
@request = request
|
@@ -75,43 +88,43 @@ module MailchimpAPI
|
|
75
88
|
end
|
76
89
|
end
|
77
90
|
|
78
|
-
# 400
|
91
|
+
# Raised when Mailchimp returns a 400 Bad Request status code
|
79
92
|
class BadRequest < FailedRequest
|
80
93
|
end
|
81
94
|
|
82
|
-
# 401
|
95
|
+
# Raised when Mailchimp returns a 401 Unauthorized status code
|
83
96
|
class Unauthorized < FailedRequest
|
84
97
|
end
|
85
98
|
|
86
|
-
# 403
|
99
|
+
# Raised when Mailchimp returns a 403 Forbidden status code
|
87
100
|
class Forbidden < FailedRequest
|
88
101
|
end
|
89
102
|
|
90
|
-
# 404
|
103
|
+
# Raised when Mailchimp returns a 404 Not Found status code
|
91
104
|
class NotFound < FailedRequest
|
92
105
|
end
|
93
106
|
|
94
|
-
# 405
|
107
|
+
# Raised when Mailchimp returns a 405 Method Not Allowed status code
|
95
108
|
class MethodNotAllowed < FailedRequest
|
96
109
|
end
|
97
110
|
|
98
|
-
# 414
|
111
|
+
# Raised when Mailchimp returns a 414 Request URI Too Long status code
|
99
112
|
class RequestURITooLong < FailedRequest
|
100
113
|
end
|
101
114
|
|
102
|
-
# 422
|
115
|
+
# Raised when Mailchimp returns a 422 Unprocessable Entity status code
|
103
116
|
class UnprocessableEntity < FailedRequest
|
104
117
|
end
|
105
118
|
|
106
|
-
# 426
|
119
|
+
# Raised when Mailchimp returns a 426 Upgrade Required status code
|
107
120
|
class UpgradeRequired < FailedRequest
|
108
121
|
end
|
109
122
|
|
110
|
-
# 429
|
123
|
+
# Raised when Mailchimp returns a 429 Too Many Requests status code
|
111
124
|
class TooManyRequests < FailedRequest
|
112
125
|
end
|
113
126
|
|
114
|
-
# 5xx
|
127
|
+
# Raised when Mailchimp returns a 5xx Server Error status code
|
115
128
|
class ServerError < FailedRequest
|
116
129
|
end
|
117
130
|
end
|
@@ -3,11 +3,11 @@
|
|
3
3
|
require "net/http"
|
4
4
|
|
5
5
|
module MailchimpAPI
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# Internal class for building failed request error instances
|
7
|
+
# @api private
|
9
8
|
class FailedRequestErrorBuilder
|
10
|
-
#
|
9
|
+
# Maps HTTP response classes to corresponding Mailchimp API error classes
|
10
|
+
# @return [Hash] Mapping of Net::HTTP response classes to MailchimpAPI::Error classes
|
11
11
|
RESPONSE_ERROR_MAP = {
|
12
12
|
Net::HTTPBadRequest => Errors::BadRequest, # 400
|
13
13
|
Net::HTTPUnauthorized => Errors::Unauthorized, # 401
|
@@ -22,13 +22,10 @@ module MailchimpAPI
|
|
22
22
|
}.freeze
|
23
23
|
|
24
24
|
class << self
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# @param
|
28
|
-
# @
|
29
|
-
#
|
30
|
-
# @return [Errors::FailedRequestError] error object
|
31
|
-
#
|
25
|
+
# Creates a new error instance based on the HTTP response
|
26
|
+
# @param request [Request] The original request that failed
|
27
|
+
# @param response [Response] The response containing the error
|
28
|
+
# @return [Errors::FailedRequest] Appropriate error instance
|
32
29
|
def call(request:, response:)
|
33
30
|
http_response = response.http_response
|
34
31
|
error_message = "#{http_response.code} #{http_response.message}"
|
@@ -39,6 +36,9 @@ module MailchimpAPI
|
|
39
36
|
|
40
37
|
private
|
41
38
|
|
39
|
+
# Determines the appropriate error class based on the HTTP response
|
40
|
+
# @param http_response [Net::HTTPResponse] The HTTP response
|
41
|
+
# @return [Class] The appropriate MailchimpAPI::Error class
|
42
42
|
def find_error_class(http_response)
|
43
43
|
found_class = RESPONSE_ERROR_MAP.keys.find { |http_error_class| http_response.is_a?(http_error_class) }
|
44
44
|
found_class ? RESPONSE_ERROR_MAP[found_class] : Errors::FailedRequest
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MailchimpAPI
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# Internal class for building network error instances
|
5
|
+
# @api private
|
7
6
|
class NetworkErrorBuilder
|
8
|
-
# List of
|
7
|
+
# List of network-related error classes that should be wrapped in NetworkError
|
8
|
+
# @return [Array<Class>] Array of error classes that indicate network issues
|
9
9
|
ERRORS = [
|
10
10
|
IOError,
|
11
11
|
Errno::ECONNABORTED,
|
@@ -20,13 +20,10 @@ module MailchimpAPI
|
|
20
20
|
].freeze
|
21
21
|
|
22
22
|
class << self
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# @param
|
26
|
-
# @
|
27
|
-
#
|
28
|
-
# @return [Errors::NetworkError] Built NetworkError
|
29
|
-
#
|
23
|
+
# Creates a new network error instance
|
24
|
+
# @param request [Request] The original request that failed
|
25
|
+
# @param error [StandardError] The original network error
|
26
|
+
# @return [Errors::NetworkError] Wrapped network error instance
|
30
27
|
def call(request:, error:)
|
31
28
|
Errors::NetworkError.new(error.message, request: request, error: error)
|
32
29
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MailchimpAPI
|
4
|
+
# Namespace for methods related to pagination
|
5
|
+
# @api private
|
6
|
+
module Pagination
|
7
|
+
# Internal module for handling pagination of list items
|
8
|
+
# @api private
|
9
|
+
module ListEachItemHelper
|
10
|
+
private
|
11
|
+
|
12
|
+
# Iterates through all items in a paginated list
|
13
|
+
# @param items_field [Symbol] The field name containing the items in the response
|
14
|
+
# @param args [Array] Arguments to pass to the list method
|
15
|
+
# @param query [Hash] Query parameters
|
16
|
+
# @param body [Hash] Request body
|
17
|
+
# @param headers [Hash] Request headers
|
18
|
+
# @yield [Hash] Each item from the list
|
19
|
+
# @return [Enumerator] If no block given
|
20
|
+
def list_each_item(items_field, *args, query: nil, body: nil, headers: nil, &block)
|
21
|
+
return enum_for(:list_each_item, items_field, *args, query: query, body: body, headers: headers) unless block
|
22
|
+
|
23
|
+
query = PrepareQueryParams.call(query, items_field: items_field)
|
24
|
+
|
25
|
+
loop do
|
26
|
+
response = list(*args, query: query, body: body, headers: headers)
|
27
|
+
response.body.fetch(items_field).each(&block)
|
28
|
+
|
29
|
+
total_received_items_count = query.fetch(:offset) + query.fetch(:count)
|
30
|
+
break if total_received_items_count >= response.body.fetch(:total_items)
|
31
|
+
|
32
|
+
query[:offset] = total_received_items_count
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MailchimpAPI
|
4
|
+
module Pagination
|
5
|
+
# Internal class for preparing query parameters for paginated requests
|
6
|
+
# @api private
|
7
|
+
class PrepareQueryParams
|
8
|
+
class << self
|
9
|
+
# Prepares query parameters for paginated requests
|
10
|
+
# @param query [Hash] Original query parameters
|
11
|
+
# @param items_field [Symbol] Field name containing the items
|
12
|
+
# @return [Hash] Prepared query parameters
|
13
|
+
def call(query, items_field:)
|
14
|
+
query ||= {}
|
15
|
+
query = query.transform_keys(&:to_sym)
|
16
|
+
|
17
|
+
prepare_offset(query)
|
18
|
+
prepare_count(query)
|
19
|
+
|
20
|
+
ensure_fields_included(query, items_field: items_field, total_field: "total_items")
|
21
|
+
ensure_fields_not_excluded(query, items_field: items_field, total_field: "total_items")
|
22
|
+
query
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def prepare_offset(query)
|
28
|
+
query[:offset] = query[:offset].to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare_count(query)
|
32
|
+
query[:count] = query[:count].to_i
|
33
|
+
query[:count] = 1000 if query[:count] == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def ensure_fields_included(query, items_field:, total_field:)
|
37
|
+
fields = query[:fields] || ""
|
38
|
+
query[:fields] = (fields.split(",") + [items_field.to_s, total_field]).uniq.join(",")
|
39
|
+
end
|
40
|
+
|
41
|
+
def ensure_fields_not_excluded(query, items_field:, total_field:)
|
42
|
+
excluded_fields = query[:excluded_fields]
|
43
|
+
return unless excluded_fields
|
44
|
+
|
45
|
+
excluded_fields = (excluded_fields.split(",") - [items_field.to_s, total_field]).join(",")
|
46
|
+
excluded_fields.empty? ? query.delete(:excluded_fields) : query[:excluded_fields] = excluded_fields
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -3,7 +3,16 @@
|
|
3
3
|
require "json"
|
4
4
|
|
5
5
|
module MailchimpAPI
|
6
|
+
# Request class for handling Mailchimp API requests
|
7
|
+
# @api public
|
6
8
|
class Request
|
9
|
+
# @return [Net::HTTP::Request] The HTTP request object
|
10
|
+
# @return [String] The initial HTTP method
|
11
|
+
# @return [String] The initial base URL
|
12
|
+
# @return [String] The initial path
|
13
|
+
# @return [Hash] The initial query parameters
|
14
|
+
# @return [Hash] The initial request body
|
15
|
+
# @return [Hash] The initial request headers
|
7
16
|
attr_reader \
|
8
17
|
:init_http_method,
|
9
18
|
:init_base_url,
|
@@ -13,7 +22,20 @@ module MailchimpAPI
|
|
13
22
|
:init_headers,
|
14
23
|
:http_request
|
15
24
|
|
16
|
-
#
|
25
|
+
# Initializes a new API request
|
26
|
+
# @param http_method [Net::HTTP::Request] HTTP method class
|
27
|
+
# @param url [String] Base URL for the request
|
28
|
+
# @param path [String] API endpoint path
|
29
|
+
# @param query [Hash] Optional query parameters
|
30
|
+
# @param body [Hash] Optional request body
|
31
|
+
# @param headers [Hash] Optional request headers
|
32
|
+
# @example
|
33
|
+
# request = MailchimpAPI::Request.new(
|
34
|
+
# Net::HTTP::Get,
|
35
|
+
# url: "https://us1.api.mailchimp.com/3.0/",
|
36
|
+
# path: "/lists",
|
37
|
+
# query: { count: 10 }
|
38
|
+
# )
|
17
39
|
def initialize(http_method, url:, path:, query: nil, body: nil, headers: nil)
|
18
40
|
@init_http_method = http_method
|
19
41
|
@init_url = url
|
@@ -29,40 +51,52 @@ module MailchimpAPI
|
|
29
51
|
|
30
52
|
@http_request = build_http_request(http_method, uri: uri, body: body, headers: headers)
|
31
53
|
end
|
32
|
-
# rubocop:enable Metrics/ParameterLists, Metrics/MethodLength
|
33
54
|
|
34
55
|
# @return [String] HTTP request method name
|
56
|
+
# @example
|
57
|
+
# request.method # => "GET"
|
35
58
|
def method
|
36
59
|
http_request.method # "GET", "POST", "PUT", "PATCH", "DELETE"
|
37
60
|
end
|
38
61
|
|
39
62
|
# @return [String] HTTP request full path
|
63
|
+
# @example
|
64
|
+
# request.path # => "/lists?count=10"
|
40
65
|
def path
|
41
66
|
http_request.path
|
42
67
|
end
|
43
68
|
|
44
69
|
# @return [URI] HTTP request URI
|
70
|
+
# @example
|
71
|
+
# request.uri # => #<URI::HTTPS https://us1.api.mailchimp.com/3.0/lists?count=10>
|
45
72
|
def uri
|
46
73
|
http_request.uri
|
47
74
|
end
|
48
75
|
|
49
76
|
# @return [String, nil] HTTP request body
|
77
|
+
# @example
|
78
|
+
# request.body # => '{"name":"New List"}'
|
50
79
|
def body
|
51
80
|
http_request.body
|
52
81
|
end
|
53
82
|
|
54
83
|
# @return [Hash] HTTP request query params
|
84
|
+
# @example
|
85
|
+
# request.query # => { count: 10 }
|
55
86
|
def query
|
56
87
|
@query ||= uri.query ? URI.decode_www_form(uri.query).to_h.transform_keys!(&:to_sym) : {}
|
57
88
|
end
|
58
89
|
|
59
90
|
# @return [Hash] HTTP request headers
|
91
|
+
# @example
|
92
|
+
# request.headers # => { "content-type" => "application/json" }
|
60
93
|
def headers
|
61
94
|
http_request.each_header.to_h
|
62
95
|
end
|
63
96
|
|
64
97
|
private
|
65
98
|
|
99
|
+
# @api private
|
66
100
|
def build_http_request(http_method, uri:, body:, headers:)
|
67
101
|
http_request = http_method.new(uri, "accept-encoding" => nil, "content-type" => "application/json")
|
68
102
|
|
@@ -72,20 +106,24 @@ module MailchimpAPI
|
|
72
106
|
http_request
|
73
107
|
end
|
74
108
|
|
109
|
+
# @api private
|
75
110
|
def prepare_uri(url, path, query)
|
76
111
|
URIBuilder.call(url: url, path: path, query: query)
|
77
112
|
end
|
78
113
|
|
114
|
+
# @api private
|
79
115
|
def prepare_headers(headers)
|
80
116
|
return {} unless headers
|
81
117
|
|
82
118
|
headers.transform_keys { |key| key.to_s.downcase }
|
83
119
|
end
|
84
120
|
|
121
|
+
# @api private
|
85
122
|
def prepare_body(body)
|
86
123
|
JSON.dump(body) unless body.nil?
|
87
124
|
end
|
88
125
|
|
126
|
+
# @api private
|
89
127
|
def prepare_http_method(default_http_method, headers)
|
90
128
|
headers["x-http-method-override"] ? Net::HTTP::Post : default_http_method
|
91
129
|
end
|
@@ -1,18 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MailchimpAPI
|
4
|
+
# Internal class for executing HTTP requests with retry logic
|
5
|
+
# @api private
|
4
6
|
class RequestExecutor
|
5
|
-
|
7
|
+
# @return [Request] The request to be executed
|
8
|
+
attr_reader :request
|
6
9
|
|
10
|
+
# @return [Hash] HTTP client configuration options
|
11
|
+
attr_reader :http_opts
|
12
|
+
|
13
|
+
# @return [Hash] Retry configuration options
|
14
|
+
attr_reader :retries
|
15
|
+
|
16
|
+
# Creates a new request executor
|
17
|
+
# @param request [Request] The request to execute
|
18
|
+
# @param http_opts [Hash] HTTP client configuration options
|
19
|
+
# @param retries [Hash] Retry configuration options
|
7
20
|
def initialize(request, http_opts: {}, retries: {})
|
8
21
|
@request = request
|
9
22
|
@http_opts = http_opts
|
10
23
|
@retries = retries
|
11
24
|
end
|
12
25
|
|
13
|
-
#
|
14
|
-
# @return [Response]
|
15
|
-
#
|
26
|
+
# Executes the request with retry logic
|
27
|
+
# @return [Response] The response from the API
|
28
|
+
# @raise [Errors::FailedRequest] If the request fails and cannot be retried
|
29
|
+
# @raise [Errors::NetworkError] If a network error occurs and cannot be retried
|
16
30
|
def call
|
17
31
|
response = execute_request
|
18
32
|
raise FailedRequestErrorBuilder.call(request: request, response: response) if response.failed?
|