wrapi 0.4.6 → 0.4.7
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/CHANGELOG.md +3 -0
- data/lib/wrapi/api.rb +36 -3
- data/lib/wrapi/authentication.rb +33 -7
- data/lib/wrapi/configuration.rb +40 -7
- data/lib/wrapi/connection.rb +68 -15
- data/lib/wrapi/entity.rb +68 -20
- data/lib/wrapi/pagination.rb +24 -13
- data/lib/wrapi/request.rb +107 -41
- data/lib/wrapi/respond_to.rb +13 -3
- data/lib/wrapi/version.rb +1 -1
- data/lib/wrapi.rb +11 -2
- metadata +3 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a4047745b71ea54dac6be7283fa0353f1e421770edf0f9940224d80bd291194
|
4
|
+
data.tar.gz: 6c8a945ec9bf4dcccfb1484b216c41e4b4582ce7ffcbfde6e47917061aee67ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c4c12660ce8746049602aed4fbe4126dd47d4e57fa4dd3092fe831093e9f15b97293d6d1baa9dddf1f7b943ad8022db12d5f2b0f56d7c8a676cb009e6cb6141
|
7
|
+
data.tar.gz: 37e5c8beebe96f750b16d076107b77e55e84d3aeec42eefad3897a539f870e4a45d7f1d8a1ac7fdd0621351e81da03a115206ec0329dc81e9bb2c3697e8a96d9
|
data/CHANGELOG.md
CHANGED
data/lib/wrapi/api.rb
CHANGED
@@ -1,15 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require File.expand_path('configuration', __dir__)
|
2
4
|
require File.expand_path('connection', __dir__)
|
3
5
|
require File.expand_path('request', __dir__)
|
4
6
|
require File.expand_path('authentication', __dir__)
|
5
7
|
|
6
8
|
module WrAPI
|
7
|
-
#
|
9
|
+
# The API class is responsible for managing the configuration and connections
|
10
|
+
# for the WrAPI library. It includes modules for handling connections, requests,
|
11
|
+
# and authentication.
|
12
|
+
#
|
13
|
+
# @attr_accessor [Hash] options Configuration options for the API instance.
|
14
|
+
#
|
15
|
+
# @example Creating a new API instance
|
16
|
+
# api = WrAPI::API.new(api_key: 'your_api_key')
|
17
|
+
#
|
18
|
+
# @example Accessing the configuration
|
19
|
+
# config = api.config
|
20
|
+
# puts config[:api_key]
|
21
|
+
#
|
22
|
+
# @see WrAPI::Connection
|
23
|
+
# @see WrAPI::Request
|
24
|
+
# @see WrAPI::Authentication
|
8
25
|
class API
|
9
|
-
# @private
|
10
26
|
attr_accessor *WrAPI::Configuration::VALID_OPTIONS_KEYS
|
11
27
|
|
12
|
-
#
|
28
|
+
# Initializes a new API object with the given options.
|
29
|
+
#
|
30
|
+
# @param options [Hash] A hash of options to configure the API object.
|
31
|
+
# The options are merged with the default options from `WrAPI.options`.
|
32
|
+
#
|
33
|
+
# @option options [String] :api_key The API key for authentication.
|
34
|
+
# @option options [String] :api_secret The API secret for authentication.
|
35
|
+
# @option options [String] :endpoint The API endpoint URL.
|
36
|
+
# @option options [String] :user_agent The User-Agent header for HTTP requests.
|
37
|
+
# @option options [Integer] :timeout The timeout for HTTP requests.
|
38
|
+
# @option options [Integer] :open_timeout The open timeout for HTTP requests.
|
39
|
+
#
|
40
|
+
# @return [WrAPI::API] A new API object configured with the given options.
|
13
41
|
def initialize(options = {})
|
14
42
|
options = WrAPI.options.merge(options)
|
15
43
|
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
@@ -17,6 +45,11 @@ module WrAPI
|
|
17
45
|
end
|
18
46
|
end
|
19
47
|
|
48
|
+
# Returns a hash of configuration options and their values.
|
49
|
+
# Iterates over each valid configuration key defined in WrAPI::Configuration::VALID_OPTIONS_KEYS,
|
50
|
+
# and assigns the corresponding value by calling the method with the same name as the key.
|
51
|
+
#
|
52
|
+
# @return [Hash] A hash containing the configuration options and their values.
|
20
53
|
def config
|
21
54
|
conf = {}
|
22
55
|
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
data/lib/wrapi/authentication.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WrAPI
|
2
4
|
# Deals with authentication flow and stores it within global configuration
|
3
5
|
# following attributes should be available:
|
@@ -7,9 +9,13 @@ module WrAPI
|
|
7
9
|
# token_type
|
8
10
|
# refresh_token
|
9
11
|
# token_expires
|
10
|
-
|
11
12
|
module Authentication
|
12
|
-
#
|
13
|
+
# Authenticates the API request by merging the provided options with the API access token parameters,
|
14
|
+
# sending a POST request to the specified path, and processing the response to extract the access token.
|
15
|
+
#
|
16
|
+
# @param path [String] the API endpoint path to which the authentication request is sent.
|
17
|
+
# @param options [Hash] additional parameters to be merged with the API access token parameters.
|
18
|
+
# @return [String] the processed access token extracted from the response body.
|
13
19
|
def api_auth(path, options = {})
|
14
20
|
params = api_access_token_params.merge(options)
|
15
21
|
response = post(path, params)
|
@@ -17,7 +23,11 @@ module WrAPI
|
|
17
23
|
api_process_token(response.body)
|
18
24
|
end
|
19
25
|
|
20
|
-
#
|
26
|
+
# Refreshes the API token by making a POST request to the specified path with the given refresh token.
|
27
|
+
#
|
28
|
+
# @param path [String] the endpoint path to send the refresh request to.
|
29
|
+
# @param token [String] the refresh token to be used for obtaining a new access token.
|
30
|
+
# @return [String] the new access token obtained from the response.
|
21
31
|
def api_refresh(path, token)
|
22
32
|
params = { refreshToken: token }
|
23
33
|
|
@@ -26,8 +36,14 @@ module WrAPI
|
|
26
36
|
api_process_token(response.body)
|
27
37
|
end
|
28
38
|
|
29
|
-
|
39
|
+
private
|
30
40
|
|
41
|
+
# Returns a hash containing the API access token parameters.
|
42
|
+
# Override this when passing different parameters
|
43
|
+
#
|
44
|
+
# @return [Hash] a hash with the following keys:
|
45
|
+
# - :username [String] the username for API authentication
|
46
|
+
# - :password [String] the password for API authentication
|
31
47
|
def api_access_token_params
|
32
48
|
{
|
33
49
|
username: username,
|
@@ -35,14 +51,24 @@ module WrAPI
|
|
35
51
|
}
|
36
52
|
end
|
37
53
|
|
54
|
+
# Processes the API response to extract and set the authentication tokens.
|
55
|
+
# Raises an ArgumentError if the response is nil.
|
56
|
+
# Override this when passing different parameters
|
57
|
+
#
|
58
|
+
# @param response [Hash] The response from the API containing authentication tokens.
|
59
|
+
# @return [String] The access token extracted from the response.
|
60
|
+
# @raise [ArgumentError] If the response is nil.
|
61
|
+
# @raise [StandardError] If the access token is not found or is empty.
|
38
62
|
def api_process_token(response)
|
39
|
-
|
63
|
+
raise ArgumentError.new("Response cannot be nil") if response.nil?
|
64
|
+
|
65
|
+
token = self.access_token = response['accessToken']
|
40
66
|
self.token_type = response['tokenType']
|
41
67
|
self.refresh_token = response['refreshToken']
|
42
68
|
self.token_expires = response['expiresIn']
|
43
|
-
raise StandardError.new
|
69
|
+
raise StandardError.new("Could not find valid accessToken; response #{response}") if token.to_s.empty?
|
44
70
|
|
45
|
-
|
71
|
+
token
|
46
72
|
end
|
47
73
|
end
|
48
74
|
end
|
data/lib/wrapi/configuration.rb
CHANGED
@@ -1,8 +1,40 @@
|
|
1
|
-
#
|
2
|
-
#require_relative './version'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
3
|
+
#
|
4
|
+
# This module defines constants and methods related to the configuration of the WrAPI.
|
5
|
+
# It provides a set of default configuration options and allows these options to be overridden.
|
6
|
+
#
|
7
|
+
# Constants:
|
8
|
+
# - VALID_OPTIONS_KEYS: An array of valid keys in the options hash when configuring a WrAPI::API.
|
9
|
+
# - DEFAULT_CONNECTION_OPTIONS: Default connection options (empty hash).
|
10
|
+
# - DEFAULT_FORMAT: Default response format (:json).
|
11
|
+
# - DEFAULT_PAGE_SIZE: Default page size for paged responses (500).
|
12
|
+
# - DEFAULT_USER_AGENT: Default user agent string.
|
13
|
+
# - DEFAULT_PAGINATION: Default pagination class.
|
14
|
+
#
|
15
|
+
# Attributes:
|
16
|
+
# - access_token: Access token for authentication.
|
17
|
+
# - token_type: Type of the token.
|
18
|
+
# - refresh_token: Token used to refresh the access token.
|
19
|
+
# - token_expires: Expiration time of the token.
|
20
|
+
# - client_id: Client ID for authentication.
|
21
|
+
# - client_secret: Client secret for authentication.
|
22
|
+
# - connection_options: Options for the connection.
|
23
|
+
# - username: Username for authentication.
|
24
|
+
# - password: Password for authentication.
|
25
|
+
# - endpoint: API endpoint.
|
26
|
+
# - logger: Logger instance.
|
27
|
+
# - format: Response format.
|
28
|
+
# - page_size: Page size for paged responses.
|
29
|
+
# - user_agent: User agent string.
|
30
|
+
# - pagination_class: Pagination class.
|
31
|
+
#
|
32
|
+
# Methods:
|
33
|
+
# - self.extended(base): Sets all configuration options to their default values when the module is extended.
|
34
|
+
# - configure: Allows configuration options to be set in a block.
|
35
|
+
# - options: Creates a hash of options and their values.
|
36
|
+
# - reset: Resets all configuration options to their default values.
|
4
37
|
module WrAPI
|
5
|
-
|
6
38
|
# Defines constants and methods related to configuration
|
7
39
|
# If configuration is overridden, please add following methods
|
8
40
|
# @see [self.extended(base)] to initialize the Configuration
|
@@ -30,7 +62,7 @@ module WrAPI
|
|
30
62
|
].freeze
|
31
63
|
|
32
64
|
# By default, don't set any connection options
|
33
|
-
DEFAULT_CONNECTION_OPTIONS = {}
|
65
|
+
DEFAULT_CONNECTION_OPTIONS = {}.freeze
|
34
66
|
|
35
67
|
# The response format appended to the path and sent in the 'Accept' header if none is set
|
36
68
|
#
|
@@ -43,11 +75,12 @@ module WrAPI
|
|
43
75
|
DEFAULT_PAGE_SIZE = 500
|
44
76
|
|
45
77
|
# The user agent that will be sent to the API endpoint if none is set
|
46
|
-
DEFAULT_USER_AGENT = "Ruby API wrapper #{WrAPI::VERSION}"
|
47
|
-
|
78
|
+
DEFAULT_USER_AGENT = "Ruby API wrapper #{WrAPI::VERSION}"
|
79
|
+
|
80
|
+
# DEFAULT_PAGINATION is a constant that sets the default pagination strategy for WrAPI requests.
|
81
|
+
# It uses the DefaultPager class from the WrAPI::RequestPagination module.
|
48
82
|
DEFAULT_PAGINATION = WrAPI::RequestPagination::DefaultPager
|
49
83
|
|
50
|
-
# @private
|
51
84
|
attr_accessor *VALID_OPTIONS_KEYS
|
52
85
|
|
53
86
|
# When this module is extended, set all configuration options to their default values
|
data/lib/wrapi/connection.rb
CHANGED
@@ -1,16 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
5
|
module WrAPI
|
4
|
-
#
|
6
|
+
# @private
|
7
|
+
# The Connection module provides methods to establish and configure a Faraday connection.
|
8
|
+
# It includes private methods to set up options, authorization, headers, and logging for the connection.
|
5
9
|
# By default
|
6
10
|
# - Bearer authorization is access_token is not nil override with @setup_authorization
|
7
11
|
# - Headers setup for client-id and client-secret when client_id and client_secret are not nil @setup_headers
|
8
|
-
#
|
12
|
+
#
|
13
|
+
# Methods:
|
14
|
+
# - connection: Establishes a Faraday connection with the configured options, authorization, headers, and logging.
|
15
|
+
# - setup_options: Sets up the options for the Faraday connection, including headers and URL.
|
16
|
+
# - setup_authorization: Configures the authorization header for the Faraday connection.
|
17
|
+
# - setup_headers: Configures additional headers for the Faraday connection.
|
18
|
+
# - setup_logger_filtering: Sets up logging and filtering for sensitive information in the Faraday connection.
|
9
19
|
module Connection
|
10
20
|
private
|
11
21
|
|
22
|
+
# Establishes a Faraday connection with the specified options and configurations.
|
23
|
+
#
|
24
|
+
# @raise [ArgumentError] if the endpoint option is not defined.
|
25
|
+
# @return [Faraday::Connection] a configured Faraday connection.
|
26
|
+
#
|
27
|
+
# The connection is configured with the following:
|
28
|
+
# - Raises errors for HTTP responses.
|
29
|
+
# - Uses the default Faraday adapter.
|
30
|
+
# - Sets up authorization and headers.
|
31
|
+
# - Parses JSON responses.
|
32
|
+
# - Uses URL-encoded requests.
|
33
|
+
# - Optionally sets up logger filtering if a logger is provided.
|
12
34
|
def connection
|
13
|
-
raise ArgumentError,
|
35
|
+
raise ArgumentError, 'Option for endpoint is not defined' unless endpoint
|
14
36
|
|
15
37
|
options = setup_options
|
16
38
|
Faraday::Connection.new(options) do |connection|
|
@@ -25,8 +47,16 @@ module WrAPI
|
|
25
47
|
end
|
26
48
|
end
|
27
49
|
|
28
|
-
# callback method to
|
29
|
-
|
50
|
+
# Sets up the options for the connection. acts as a callback method to
|
51
|
+
# setup api authorization
|
52
|
+
#
|
53
|
+
# @return [Hash] A hash containing the headers and URL for the connection,
|
54
|
+
# merged with any additional connection options.
|
55
|
+
# @option options [Hash] :headers The headers for the connection, including:
|
56
|
+
# - 'Accept' [String]: The content type to accept, based on the format.
|
57
|
+
# - 'User-Agent' [String]: The user agent string.
|
58
|
+
# @option options [String] :url The endpoint URL for the connection.
|
59
|
+
def setup_options
|
30
60
|
{
|
31
61
|
headers: {
|
32
62
|
'Accept': "application/#{format}; charset=utf-8",
|
@@ -36,26 +66,49 @@ module WrAPI
|
|
36
66
|
}.merge(connection_options || {})
|
37
67
|
end
|
38
68
|
|
39
|
-
#
|
69
|
+
# Sets up the authorization header for the given connection.
|
70
|
+
# override to setup your own header for api authorization
|
71
|
+
#
|
72
|
+
# @param connection [Object] The connection object to which the authorization header will be added.
|
73
|
+
# @return [void]
|
74
|
+
# @note The authorization header will only be set if the access_token is present.
|
40
75
|
def setup_authorization(connection)
|
41
76
|
connection.headers['Authorization'] = "Bearer #{access_token}" if access_token
|
42
77
|
end
|
43
78
|
|
44
|
-
#
|
79
|
+
# Sets up the headers for the given connection. Override to set own headers.
|
80
|
+
#
|
81
|
+
# @param connection [Object] The connection object to set headers on.
|
82
|
+
# @option connection.headers [String] 'client-id' The client ID, if available.
|
83
|
+
# @option connection.headers [String] 'client-secret' The client secret, if available.
|
84
|
+
#
|
85
|
+
# @return [void]
|
45
86
|
def setup_headers(connection)
|
46
87
|
connection.headers['client-id'] = client_id if client_id
|
47
88
|
connection.headers['client-secret'] = client_secret if client_secret
|
48
89
|
end
|
49
90
|
|
50
|
-
#
|
91
|
+
# Sets up logger filtering for the given connection.
|
92
|
+
#
|
93
|
+
# This method configures the logger to filter sensitive information from the
|
94
|
+
# connection's response. It filters out passwords, access tokens, client secrets,
|
95
|
+
# and authorization headers from the logs.
|
96
|
+
#
|
97
|
+
# @param connection [Faraday::Connection] The connection object to configure the logger for.
|
98
|
+
# @param logger [Logger] The logger instance to use for logging the connection's responses.
|
99
|
+
#
|
100
|
+
# @example
|
101
|
+
# setup_logger_filtering(connection, logger)
|
102
|
+
#
|
103
|
+
# @note This method assumes that the connection object is a Faraday connection.
|
51
104
|
def setup_logger_filtering(connection, logger)
|
52
|
-
connection.response :logger, logger, { headers: true, bodies: true } do |
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
# filter header content
|
57
|
-
|
58
|
-
|
105
|
+
connection.response :logger, logger, { headers: true, bodies: true } do |log|
|
106
|
+
# Filter sensitive information from JSON content, such as passwords and access tokens.
|
107
|
+
log.filter(/("password":")(.+?)(".*)/, '\1[REMOVED]\3')
|
108
|
+
log.filter(/("[Aa]ccess_?[Tt]oken":")(.+?)(".*)/, '\1[REMOVED]\3')
|
109
|
+
# filter sensitive header content such as client secrets and authorization headers
|
110
|
+
log.filter(/(client[-_]secret[:=].)([^&]+)/, '\1[REMOVED]')
|
111
|
+
log.filter(/(Authorization:.)([^&]+)/, '\1[REMOVED]')
|
59
112
|
end
|
60
113
|
end
|
61
114
|
end
|
data/lib/wrapi/entity.rb
CHANGED
@@ -1,18 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
|
5
|
+
# This module defines the WrAPI namespace which is used to encapsulate all the classes and modules
|
6
|
+
# related to the WrAPI library. The WrAPI library provides functionality for interacting with APIs.
|
3
7
|
module WrAPI
|
4
8
|
# Defines HTTP request methods
|
5
9
|
module Request
|
10
|
+
# Entity class to represent and manipulate API data
|
6
11
|
class Entity
|
7
|
-
#
|
12
|
+
# Factory method to create an entity or array of entities
|
13
|
+
#
|
14
|
+
# @param attr [Hash, Array<Hash>] the attributes to create the entity/entities from
|
15
|
+
# @return [Entity, Array<Entity>] the created entity or array of entities
|
8
16
|
def self.create(attr)
|
9
17
|
if attr.is_a? Array
|
10
18
|
Entity.entify(attr)
|
11
|
-
|
12
|
-
Entity.new(attr)
|
19
|
+
elsif attr
|
20
|
+
Entity.new(attr)
|
13
21
|
end
|
14
22
|
end
|
15
23
|
|
24
|
+
# Initializes a new Entity
|
25
|
+
#
|
26
|
+
# @param attr [Hash] the attributes to initialize the entity with
|
16
27
|
def initialize(attr)
|
17
28
|
case attr
|
18
29
|
when Hash
|
@@ -21,30 +32,47 @@ module WrAPI
|
|
21
32
|
@attributes = attr.clone
|
22
33
|
end
|
23
34
|
end
|
24
|
-
|
35
|
+
|
36
|
+
# Returns the attributes of the entity
|
37
|
+
#
|
38
|
+
# @return [Hash] the attributes of the entity
|
25
39
|
def attributes
|
26
40
|
@attributes || {}
|
27
41
|
end
|
28
42
|
|
29
|
-
|
43
|
+
# Sets the attributes of the entity
|
44
|
+
#
|
45
|
+
# @param val [Hash] the new attributes of the entity
|
46
|
+
def attributes=(val)
|
30
47
|
@attributes = val || {}
|
31
48
|
end
|
32
49
|
|
50
|
+
# Handles dynamic method calls for attribute access and assignment
|
51
|
+
#
|
52
|
+
# @param method_sym [Symbol] the method name
|
53
|
+
# @param arguments [Array] the arguments passed to the method
|
54
|
+
# @param block [Proc] an optional block
|
33
55
|
def method_missing(method_sym, *arguments, &block)
|
34
56
|
# assignment
|
57
|
+
method = method_sym.to_s
|
35
58
|
assignment = method_sym[/.*(?==\z)/m]
|
36
59
|
if assignment
|
37
60
|
raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1)", caller(1) unless arguments.length == 1
|
38
61
|
|
39
62
|
@attributes[assignment] = arguments[0]
|
40
|
-
elsif @attributes.include?
|
41
|
-
accessor(
|
63
|
+
elsif @attributes.include? method
|
64
|
+
accessor(method)
|
42
65
|
else
|
43
66
|
# delegate to hash
|
44
67
|
@attributes.send(method_sym, *arguments, &block)
|
45
68
|
end
|
46
69
|
end
|
47
70
|
|
71
|
+
# Checks if the entity responds to a method
|
72
|
+
#
|
73
|
+
# @param method_sym [Symbol] the method name
|
74
|
+
# @param include_private [Boolean] whether to include private methods
|
75
|
+
# @return [Boolean] true if the entity responds to the method, false otherwise
|
48
76
|
def respond_to?(method_sym, include_private = false)
|
49
77
|
@attributes ||= {}
|
50
78
|
if @attributes.include? method_sym.to_s
|
@@ -54,41 +82,61 @@ module WrAPI
|
|
54
82
|
end
|
55
83
|
end
|
56
84
|
|
57
|
-
|
85
|
+
# Converts the entity to a JSON string
|
86
|
+
#
|
87
|
+
# @param options [Hash] options for JSON generation
|
88
|
+
# @return [String] the JSON representation of the entity
|
89
|
+
def to_json(_options = {})
|
58
90
|
@attributes.to_json
|
59
91
|
end
|
60
92
|
|
93
|
+
# Accesses an attribute, converting it to an Entity if it is a Hash or Array
|
94
|
+
#
|
95
|
+
# @param method [String] the attribute name
|
96
|
+
# @return [Object] the attribute value
|
61
97
|
def accessor(method)
|
62
|
-
|
98
|
+
attribute = @attributes[method]
|
99
|
+
case attribute
|
63
100
|
when Hash
|
64
|
-
@attributes[method] = self.class.new(
|
101
|
+
@attributes[method] = self.class.new(attribute)
|
65
102
|
when Array
|
66
103
|
# make deep copy
|
67
|
-
@attributes[method] = Entity.entify(
|
104
|
+
@attributes[method] = Entity.entify(attribute)
|
68
105
|
else
|
69
|
-
|
106
|
+
attribute
|
70
107
|
end
|
71
108
|
end
|
72
|
-
|
109
|
+
|
110
|
+
# Clones the entity
|
111
|
+
#
|
112
|
+
# @return [Entity] the cloned entity
|
73
113
|
def clone
|
74
|
-
|
75
|
-
|
76
|
-
|
114
|
+
cln = super
|
115
|
+
cln.attributes = @attributes.clone
|
116
|
+
cln
|
77
117
|
end
|
78
118
|
|
119
|
+
# Checks if two entities are equal
|
120
|
+
#
|
121
|
+
# @param other [Entity] the other entity to compare with
|
122
|
+
# @return [Boolean] true if the entities are equal, false otherwise
|
79
123
|
def ==(other)
|
80
124
|
(self.class == other.class) && (self.attributes.eql? other.attributes)
|
81
125
|
end
|
82
126
|
alias eql? ==
|
83
127
|
|
84
|
-
|
85
|
-
|
86
|
-
|
128
|
+
# Converts an array of hashes to an array of entities
|
129
|
+
#
|
130
|
+
# @param attribute [Array<Hash>] the array of hashes
|
131
|
+
# @return [Array<Entity>] the array of entities
|
132
|
+
def self.entify(attribute)
|
133
|
+
if attribute.any? && (attribute.first.is_a? Hash)
|
134
|
+
attribute.dup.map do |item|
|
87
135
|
#item.is_a?(Hash) ? self.class.new(item) : item
|
88
136
|
Entity.create(item)
|
89
137
|
end
|
90
138
|
else
|
91
|
-
|
139
|
+
attribute
|
92
140
|
end
|
93
141
|
end
|
94
142
|
end
|
data/lib/wrapi/pagination.rb
CHANGED
@@ -1,39 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'json'
|
3
5
|
|
4
6
|
module WrAPI
|
5
|
-
# Defines HTTP request methods
|
6
|
-
# required attributes format
|
7
|
+
# Defines HTTP request methods and required attributes format for pagination.
|
7
8
|
module RequestPagination
|
8
|
-
|
9
|
-
# Defaut pages asumes all data retrieved in a single go.
|
9
|
+
# DefaultPager handles pagination by assuming all data is retrieved in a single go.
|
10
10
|
class DefaultPager
|
11
|
-
|
12
|
-
#
|
13
|
-
|
11
|
+
# Initializes the pager with an optional page size.
|
12
|
+
#
|
13
|
+
# @param _page_size [Integer, nil] the size of the page (not used in this implementation)
|
14
|
+
def initialize(_page_size = nil)
|
14
15
|
@page = 0
|
15
16
|
end
|
16
17
|
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
18
|
+
# Advances to the next page.
|
19
|
+
#
|
20
|
+
# @param _data [Object, nil] the data from the current page (not used in this implementation)
|
21
|
+
# @return [Boolean] true if there are more pages, false otherwise
|
22
|
+
def next_page!(_data = nil)
|
20
23
|
@page += 1
|
21
24
|
more_pages?
|
22
25
|
end
|
23
26
|
|
24
|
-
#
|
27
|
+
# Checks if there are more pages.
|
28
|
+
#
|
29
|
+
# @return [Boolean] true if there are more pages, false otherwise
|
25
30
|
def more_pages?
|
26
31
|
@page < 1
|
27
32
|
end
|
28
33
|
|
34
|
+
# Returns options for the current page to add to get request.
|
35
|
+
#
|
36
|
+
# @return [Hash] an empty hash as options
|
29
37
|
def page_options
|
30
38
|
{}
|
31
39
|
end
|
32
40
|
|
33
|
-
|
41
|
+
# Processes the data from the response body.
|
42
|
+
#
|
43
|
+
# @param body [Object] the response body
|
44
|
+
# @return [Object] the processed data (in this case, the body itself)
|
45
|
+
def self.data(body)
|
34
46
|
body
|
35
47
|
end
|
36
48
|
end
|
37
|
-
|
38
49
|
end
|
39
50
|
end
|
data/lib/wrapi/request.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'json'
|
3
5
|
|
4
6
|
module WrAPI
|
5
7
|
# Defines HTTP request methods
|
6
|
-
# required attributes format
|
7
8
|
module Request
|
8
9
|
CONTENT_TYPE_HDR = 'Content-Type'.freeze
|
9
|
-
|
10
|
-
#
|
11
|
-
|
10
|
+
|
11
|
+
# Perform an HTTP GET request and return entity in case format is :json
|
12
|
+
#
|
13
|
+
# @param path [String] the request path
|
14
|
+
# @param options [Hash] the request options
|
15
|
+
# @param raw [Boolean] whether to return raw response
|
16
|
+
# @return [Entity, String] the response entity or raw response body
|
17
|
+
def get(path, options = {}, raw = false)
|
12
18
|
response = request(:get, path, options) do |request|
|
13
19
|
# inject headers...
|
14
20
|
yield(request) if block_given?
|
@@ -16,34 +22,43 @@ module WrAPI
|
|
16
22
|
entity_response(response, raw)
|
17
23
|
end
|
18
24
|
|
19
|
-
# Perform an HTTP GET request for paged
|
20
|
-
#
|
25
|
+
# Perform an HTTP GET request for paged data sets response
|
26
|
+
#
|
27
|
+
# @param path [String] the request path
|
28
|
+
# @param options [Hash] the request options
|
29
|
+
# @param request_labda [Proc] an optional lambda to modify the request
|
30
|
+
# @return [Array<Entity>, nil] the concatenated result set or nil if block given
|
21
31
|
def get_paged(path, options = {}, request_labda = nil)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# inject headers...
|
30
|
-
request_labda.call(req) if request_labda
|
31
|
-
end
|
32
|
-
handle_data(response.body,pager) do |d|
|
33
|
-
if block_given?
|
34
|
-
yield(d)
|
35
|
-
else
|
36
|
-
result = add_data(result,d)
|
32
|
+
if is_json?
|
33
|
+
result = []
|
34
|
+
pager = create_pager
|
35
|
+
while pager.more_pages?
|
36
|
+
response = request(:get, path, options.merge(pager.page_options)) do |req|
|
37
|
+
# inject headers...
|
38
|
+
request_labda&.call(req)
|
37
39
|
end
|
40
|
+
handle_data(response.body, pager) do |d|
|
41
|
+
if block_given?
|
42
|
+
yield(d)
|
43
|
+
else
|
44
|
+
result = add_data(result, d)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
pager.next_page!(response.body)
|
38
48
|
end
|
39
|
-
|
49
|
+
result unless block_given?
|
50
|
+
else
|
51
|
+
raise ArgumentError, "Pages requests should be json formatted (given format '#{format}')"
|
40
52
|
end
|
41
|
-
result unless block_given?
|
42
53
|
end
|
43
54
|
|
44
55
|
# Perform an HTTP POST request
|
45
|
-
#
|
46
|
-
|
56
|
+
#
|
57
|
+
# @param path [String] the request path
|
58
|
+
# @param options [Hash] the request options
|
59
|
+
# @param raw [Boolean] whether to return raw response
|
60
|
+
# @return [Entity, String] the response entity or raw response body
|
61
|
+
def post(path, options = {}, raw = true)
|
47
62
|
response = request(:post, path, options) do |request|
|
48
63
|
yield(request) if block_given?
|
49
64
|
end
|
@@ -51,8 +66,12 @@ module WrAPI
|
|
51
66
|
end
|
52
67
|
|
53
68
|
# Perform an HTTP PUT request
|
54
|
-
#
|
55
|
-
|
69
|
+
#
|
70
|
+
# @param path [String] the request path
|
71
|
+
# @param options [Hash] the request options
|
72
|
+
# @param raw [Boolean] whether to return raw response
|
73
|
+
# @return [Entity, String] the response entity or raw response body
|
74
|
+
def put(path, options = {}, raw = true)
|
56
75
|
response = request(:put, path, options) do |request|
|
57
76
|
yield(request) if block_given?
|
58
77
|
end
|
@@ -60,44 +79,66 @@ module WrAPI
|
|
60
79
|
end
|
61
80
|
|
62
81
|
# Perform an HTTP DELETE request
|
63
|
-
#
|
64
|
-
|
82
|
+
#
|
83
|
+
# @param path [String] the request path
|
84
|
+
# @param options [Hash] the request options
|
85
|
+
# @param raw [Boolean] whether to return raw response
|
86
|
+
# @return [Entity, String] the response entity or raw response body
|
87
|
+
def delete(path, options = {}, raw = false)
|
65
88
|
response = request(:delete, path, options) do |request|
|
66
89
|
yield(request) if block_given?
|
67
90
|
end
|
68
91
|
entity_response(response, raw)
|
69
92
|
end
|
70
93
|
|
94
|
+
# Checks if the response format is JSON
|
95
|
+
#
|
96
|
+
# @return [Boolean] true if the format is JSON, false otherwise
|
71
97
|
def is_json?
|
72
98
|
format && 'json'.eql?(format.to_s)
|
73
99
|
end
|
74
100
|
|
75
|
-
|
101
|
+
private
|
76
102
|
|
103
|
+
# Creates a pager for paginated requests
|
104
|
+
#
|
105
|
+
# @return [Object] the pager instance
|
77
106
|
def create_pager
|
78
107
|
pagination_class ? pagination_class.new(page_size) : WrAPI::RequestPagination::DefaultPager
|
79
108
|
end
|
80
109
|
|
81
110
|
# Perform an HTTP request
|
111
|
+
#
|
112
|
+
# @param method [Symbol] the HTTP method
|
113
|
+
# @param path [String] the request path
|
114
|
+
# @param options [Hash] the request options
|
115
|
+
# @yieldparam request [Object] the request object
|
116
|
+
# @return [Object] the response object
|
82
117
|
def request(method, path, options)
|
83
118
|
response = connection.send(method) do |request|
|
84
|
-
|
119
|
+
if block_given?
|
120
|
+
yield(request)
|
121
|
+
end
|
85
122
|
request.headers[CONTENT_TYPE_HDR] = "application/#{format}" unless request.headers[CONTENT_TYPE_HDR]
|
86
|
-
|
87
|
-
_path =
|
88
|
-
_path.path = uri.escape(_path.path)
|
123
|
+
|
124
|
+
_path = escape_path(path)
|
89
125
|
case method
|
90
126
|
when :get, :delete
|
91
127
|
request.url(_path.to_s, options)
|
92
128
|
when :post, :put
|
93
129
|
request.path = _path.to_s
|
94
|
-
set_body(request,options)
|
130
|
+
set_body(request, options)
|
95
131
|
end
|
96
132
|
end
|
97
133
|
response
|
98
134
|
end
|
99
135
|
|
100
|
-
|
136
|
+
# Processes the response and returns an entity if format is JSON
|
137
|
+
#
|
138
|
+
# @param response [Object] the response object
|
139
|
+
# @param raw [Boolean] whether to return raw response
|
140
|
+
# @return [Entity, Object] the response entity or raw response
|
141
|
+
def entity_response(response, raw = false)
|
101
142
|
if is_json? && !raw
|
102
143
|
Entity.create(pagination_class.data(response.body))
|
103
144
|
else
|
@@ -105,27 +146,52 @@ module WrAPI
|
|
105
146
|
end
|
106
147
|
end
|
107
148
|
|
108
|
-
#
|
109
|
-
|
149
|
+
# Sets the request body depending on the content type
|
150
|
+
#
|
151
|
+
# @param request [Object] the request object
|
152
|
+
# @param options [Hash] the request options
|
153
|
+
def set_body(request, options)
|
110
154
|
if is_json? && !options.empty?
|
111
155
|
request.body = options.to_json
|
112
156
|
else
|
113
157
|
request.body = URI.encode_www_form(options) unless options.empty?
|
114
158
|
end
|
115
159
|
end
|
116
|
-
|
160
|
+
|
161
|
+
# Handles the data in the response body
|
162
|
+
#
|
163
|
+
# @param body [String] the response body
|
164
|
+
# @param pager [Object] the pager instance
|
165
|
+
# @yieldparam data [Object] the data in the response body
|
166
|
+
def handle_data(body, pager)
|
117
167
|
if d = pager.class.data(body)
|
118
168
|
d = Entity.create(d)
|
119
169
|
yield(d) if block_given?
|
120
170
|
end
|
121
171
|
end
|
122
|
-
|
123
|
-
|
172
|
+
|
173
|
+
# Adds data to the result array and checks if data itself is an array
|
174
|
+
#
|
175
|
+
# @param result [Array] the result array
|
176
|
+
# @param data [Object] the data to add
|
177
|
+
# @return [Array] the updated result array
|
178
|
+
def add_data(result, data)
|
124
179
|
if data.is_a? Array
|
125
180
|
result += data
|
126
181
|
else
|
127
182
|
result << data
|
128
183
|
end
|
129
184
|
end
|
185
|
+
|
186
|
+
# Escapes the request path
|
187
|
+
#
|
188
|
+
# @param path [String] the request path
|
189
|
+
# @return [URI::Generic] the escaped path
|
190
|
+
def escape_path(path)
|
191
|
+
uri = URI::Parser.new
|
192
|
+
_path = uri.parse(path)
|
193
|
+
_path.path = URI::RFC2396_PARSER.escape(_path.path)
|
194
|
+
_path
|
195
|
+
end
|
130
196
|
end
|
131
197
|
end
|
data/lib/wrapi/respond_to.rb
CHANGED
@@ -1,14 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module WrAPI
|
4
|
+
# Module to delegate methods to the Client
|
3
5
|
module RespondTo
|
4
|
-
|
5
|
-
#
|
6
|
+
# Delegate method calls to the Client
|
7
|
+
#
|
8
|
+
# @param method [Symbol] the method name
|
9
|
+
# @param args [Array] the arguments passed to the method
|
10
|
+
# @param block [Proc] an optional block
|
6
11
|
def self.method_missing(method, *args, &block)
|
7
12
|
return super unless client.respond_to?(method)
|
13
|
+
|
8
14
|
client.send(method, *args, &block)
|
9
15
|
end
|
10
16
|
|
11
|
-
#
|
17
|
+
# Checks if the Client responds to a method
|
18
|
+
#
|
19
|
+
# @param method [Symbol] the method name
|
20
|
+
# @param include_all [Boolean] whether to include private methods
|
21
|
+
# @return [Boolean] true if the Client responds to the method, false otherwise
|
12
22
|
def self.respond_to?(method, include_all = false)
|
13
23
|
client.respond_to?(method, include_all) || super
|
14
24
|
end
|
data/lib/wrapi/version.rb
CHANGED
data/lib/wrapi.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require File.expand_path('wrapi/version', __dir__)
|
2
4
|
require File.expand_path('wrapi/pagination', __dir__)
|
3
5
|
require File.expand_path('wrapi/configuration', __dir__)
|
@@ -8,6 +10,13 @@ require File.expand_path('wrapi/request', __dir__)
|
|
8
10
|
require File.expand_path('wrapi/respond_to', __dir__)
|
9
11
|
require File.expand_path('wrapi/authentication', __dir__)
|
10
12
|
|
13
|
+
# WrAPI module provides a structure for creating API wrappers.
|
14
|
+
# It extends RespondTo and Configuration modules to include their functionalities.
|
15
|
+
#
|
16
|
+
# Methods:
|
17
|
+
# - self.client(_options = {}): Abstract method that should be overridden in the including class.
|
18
|
+
# Raises NotImplementedError if not implemented.
|
19
|
+
# - self.reset: Resets the configuration to defaults and sets the user agent string.
|
11
20
|
module WrAPI
|
12
21
|
extend RespondTo
|
13
22
|
extend Configuration
|
@@ -15,13 +24,13 @@ module WrAPI
|
|
15
24
|
# Abstract method should be overridden
|
16
25
|
#
|
17
26
|
# @return client
|
18
|
-
def self.client(
|
27
|
+
def self.client(_options = {})
|
19
28
|
raise NotImplementedError, 'Abstract method self.client must implemented when including ResponTo'
|
20
29
|
end
|
21
30
|
|
22
31
|
# set/override defaults
|
23
32
|
def self.reset
|
24
33
|
super
|
25
|
-
self.user_agent = "Ruby API wrapper #{WrAPI::VERSION}"
|
34
|
+
self.user_agent = "Ruby API wrapper #{WrAPI::VERSION}"
|
26
35
|
end
|
27
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wrapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janco Tanis
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-18 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: faraday
|
@@ -80,7 +79,6 @@ dependencies:
|
|
80
79
|
- - ">="
|
81
80
|
- !ruby/object:Gem::Version
|
82
81
|
version: '0'
|
83
|
-
description:
|
84
82
|
email: gems@jancology.com
|
85
83
|
executables: []
|
86
84
|
extensions: []
|
@@ -109,7 +107,6 @@ licenses:
|
|
109
107
|
metadata:
|
110
108
|
homepage_uri: https://rubygems.org/gems/wrapi
|
111
109
|
source_code_uri: https://github.com/jancotanis/wrapi
|
112
|
-
post_install_message:
|
113
110
|
rdoc_options: []
|
114
111
|
require_paths:
|
115
112
|
- lib
|
@@ -124,8 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
121
|
- !ruby/object:Gem::Version
|
125
122
|
version: '0'
|
126
123
|
requirements: []
|
127
|
-
rubygems_version: 3.2
|
128
|
-
signing_key:
|
124
|
+
rubygems_version: 3.6.2
|
129
125
|
specification_version: 4
|
130
126
|
summary: A Ruby api wrapper code extracted from real world api clients
|
131
127
|
test_files: []
|