messagemedia_lookups_sdk 1.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.
@@ -0,0 +1,35 @@
1
+
2
+ module MessageMediaLookups
3
+
4
+ Logging.logger.root.appenders = Logging.appenders.stdout
5
+ Logging.logger.root.level = :info
6
+
7
+ # All configuration including auth info and base URI for the API access
8
+ # are configured in this class.
9
+ class Configuration
10
+ # The base Uri for API calls
11
+ @base_uri = 'https://api.messagemedia.com'
12
+
13
+ # The username to use with basic authentication
14
+ @basic_auth_user_name = 'TODO: Replace'
15
+
16
+ # The password to use with basic authentication
17
+ @basic_auth_password = 'TODO: Replace'
18
+
19
+ # The username to use with HMAC authentication
20
+ @hmac_auth_user_name = nil
21
+
22
+ # The password to use with HMAC authentication
23
+ @hmac_auth_password = nil
24
+
25
+ # The attribute accessors for public properties.
26
+ class << self
27
+ attr_accessor :array_serialization
28
+ attr_accessor :base_uri
29
+ attr_accessor :basic_auth_user_name
30
+ attr_accessor :basic_auth_password
31
+ attr_accessor :hmac_auth_user_name
32
+ attr_accessor :hmac_auth_password
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,63 @@
1
+
2
+ module MessageMediaLookups
3
+ # Base controller.
4
+ class BaseController
5
+ attr_accessor :http_client, :http_call_back
6
+
7
+ def initialize(http_client: nil, http_call_back: nil)
8
+ @http_client = http_client || FaradayClient.new
9
+ @http_call_back = http_call_back
10
+
11
+ @global_headers = {
12
+ 'user-agent' => 'messagemedia-lookups-ruby-sdk-1.0.0'
13
+ }
14
+ @logger = Logging.logger[self]
15
+ @logger.info("Instantiated controller class.")
16
+ end
17
+
18
+ def validate_parameters(args)
19
+ args.each do |_name, value|
20
+ if value.nil?
21
+ raise ArgumentError, "Required parameter #{_name} cannot be nil."
22
+ end
23
+ end
24
+ end
25
+
26
+ def apply_authentication(request, url, body=nil)
27
+ if Configuration.hmac_auth_user_name == nil or Configuration.hmac_auth_password == nil
28
+ BasicAuth.apply(request)
29
+ else
30
+ HmacAuth.apply(request, url, body)
31
+ end
32
+ end
33
+
34
+ def execute_request(request, binary: false, name: nil)
35
+ @logger.info("Calling the on_before_request method of http_call_back for #{name}.") if @http_call_back
36
+ @http_call_back.on_before_request(request) if @http_call_back
37
+
38
+ @logger.info("Merging global headers with endpoint headers for #{name}.")
39
+ APIHelper.clean_hash(request.headers)
40
+ request.headers = @global_headers.clone.merge(request.headers)
41
+
42
+ @logger.debug("Raw request for #{name} is: #{request.inspect}")
43
+ response = if binary
44
+ @http_client.execute_as_binary(request)
45
+ else
46
+ @http_client.execute_as_string(request)
47
+ end
48
+ @logger.debug("Raw response for #{name} is: #{response.inspect}")
49
+ @logger.info("Wrapping request and response in a context object for #{name}.")
50
+ context = HttpContext.new(request, response)
51
+
52
+ @logger.info("Calling on_after_response method of http_call_back for #{name}.") if @http_call_back
53
+ @http_call_back.on_after_response(context) if @http_call_back
54
+
55
+ context
56
+ end
57
+
58
+ def validate_response(context)
59
+ raise APIException.new 'HTTP Response Not OK', context unless
60
+ context.response.status_code.between?(200, 208) # [200,208] = HTTP OK
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,121 @@
1
+
2
+ module MessageMediaLookups
3
+ # LookupsController
4
+ class LookupsController < BaseController
5
+ @instance = LookupsController.new
6
+
7
+ class << self
8
+ attr_accessor :instance
9
+ end
10
+
11
+ def instance
12
+ self.class.instance
13
+ end
14
+
15
+ # Use the Lookups API to find information about a phone number.
16
+ # A request to the lookups API has the following format:
17
+ # ```/v1/lookups/phone/{phone_number}?options={carrier,type}```
18
+ # The `{phone_number}` parameter is a required field and should be set to
19
+ # the phone number to be looked up.
20
+ # The options query parameter can also be used to request additional
21
+ # information about the phone number.
22
+ # By default, a request will only return the `country_code` and
23
+ # `phone_number` properties in the response.
24
+ # To request details about the the carrier, include `carrier` as a value of
25
+ # the options parameter.
26
+ # To request details about the type, include `type` as a value of the
27
+ # options parameter. To pass multiple values
28
+ # to the options parameter, use a comma separated list, i.e. `carrier,type`.
29
+ # A successful request to the lookups endpoint will return a response body
30
+ # as follows:
31
+ # ```json
32
+ # {
33
+ # "country_code": "AU",
34
+ # "phone_number": "+61491570156",
35
+ # "type": "mobile",
36
+ # "carrier": {
37
+ # "name": "Telstra"
38
+ # }
39
+ # }
40
+ # ```
41
+ # Each property in the response body is defined as follows:
42
+ # - ```country_code``` ISO ALPHA 2 country code of the phone number
43
+ # - ```phone_number``` E.164 formatted phone number
44
+ # - ```type``` The type of number. This can be ```"mobile"``` or
45
+ # ```"landline"```
46
+ # - ```carrier``` Holds information about the specific carrier (if
47
+ # available)
48
+ # - ```name``` The carrier's name as reported by the network
49
+ # @param [String] phone_number Required parameter: The phone number to be
50
+ # looked up
51
+ # @param [String] options Optional parameter: Example:
52
+ # @return LookupAPhoneNumberResponse response from the API call
53
+ def get_lookup_a_phone_number(phone_number,
54
+ options = nil)
55
+ begin
56
+ @logger.info("get_lookup_a_phone_number called.")
57
+
58
+ request_url = '/v1/lookups/phone/{phone_number}'
59
+ request_url = APIHelper.append_url_with_template_parameters(
60
+ request_url,
61
+ 'phone_number' => phone_number
62
+ )
63
+
64
+ # Prepare query url.
65
+ @logger.info("Preparing query URL for get_lookup_a_phone_number.")
66
+ _query_builder = Configuration.base_uri.dup
67
+ _query_builder << '/v1/lookups/phone/{phone_number}'
68
+ _query_builder = APIHelper.append_url_with_template_parameters(
69
+ _query_builder,
70
+ 'phone_number' => phone_number
71
+ )
72
+ _query_builder = APIHelper.append_url_with_query_parameters(
73
+ _query_builder,
74
+ {
75
+ 'options' => options
76
+ },
77
+ array_serialization: Configuration.array_serialization
78
+ )
79
+ _query_url = APIHelper.clean_url _query_builder
80
+
81
+ # Prepare headers.
82
+ @logger.info("Preparing headers for get_lookup_a_phone_number.")
83
+ _headers = {
84
+ 'accept' => 'application/json',
85
+ 'user-agent' => 'messagemedia-lookups-ruby-sdk-1.1.0'
86
+ }
87
+
88
+ # Prepare and execute HttpRequest.
89
+ @logger.info('Preparing and executing HttpRequest for get_lookup_a_phone_number.')
90
+ _request = @http_client.get(
91
+ _query_url,
92
+ headers: _headers
93
+ )
94
+
95
+ apply_authentication(_request, request_url)
96
+ # BasicAuth.apply(_request)
97
+
98
+ _context = execute_request(_request, name: 'get_lookup_a_phone_number')
99
+
100
+ # Validate response against endpoint and global error codes.
101
+ @logger.info("Validating response for get_lookup_a_phone_number.")
102
+ if _context.response.status_code == 404
103
+ raise APIException.new(
104
+ 'Number was invalid',
105
+ _context
106
+ )
107
+ end
108
+ validate_response(_context)
109
+
110
+ # Return appropriate response type.
111
+ @logger.info("Returning response for get_lookup_a_phone_number.")
112
+ decoded = APIHelper.json_deserialize(_context.response.raw_body)
113
+ LookupAPhoneNumberResponse.from_hash(decoded)
114
+
115
+ rescue Exception => e
116
+ @logger.error(e)
117
+ raise e
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module MessageMediaLookups
3
+ # Class for exceptions when there is a network error, status code error, etc.
4
+ class APIException < StandardError
5
+ attr_reader :context, :response_code
6
+
7
+ # The constructor.
8
+ # @param [String] The reason for raising an exception.
9
+ # @param [HttpContext] The HttpContext of the API call.
10
+ def initialize(reason, context)
11
+ super(reason)
12
+ @context = context
13
+ @response_code = context.response.status_code
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+
2
+ require 'base64'
3
+
4
+ module MessageMediaLookups
5
+ # Utility class for basic authorization.
6
+ class BasicAuth
7
+ # Add basic authentication to the request.
8
+ # @param [HttpRequest] The HttpRequest object to which authentication will
9
+ # be added.
10
+ def self.apply(http_request)
11
+ username = Configuration.basic_auth_user_name
12
+ password = Configuration.basic_auth_password
13
+ if(username.length != 20 || password.length != 30)
14
+ puts("~~~~~ It appears as though your REST API Keys are invalid. Please check and make sure they are correct. (Invalid Length) ~~~~~")
15
+ end
16
+ value = Base64.strict_encode64("#{username}:#{password}")
17
+ header_value = "Basic #{value}"
18
+ http_request.headers['Authorization'] = header_value
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+
2
+ require 'base64'
3
+
4
+ module MessageMediaMessages
5
+ # Utility class for basic authorization.
6
+ class HmacAuth
7
+ def self.create_signature(date, content_signature, url, body=nil)
8
+ request_type = "GET"
9
+
10
+ if body != nil
11
+ request_type = "POST"
12
+ end
13
+
14
+ signing_string = "date: #{date}\n#{content_signature}#{request_type} #{url} HTTP/1.1"
15
+ hmac = OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), Configuration.hmac_auth_password.encode("ASCII"), signing_string.encode("ASCII"))
16
+
17
+ return Base64.encode64(hmac).chomp
18
+ end
19
+
20
+ # Add basic authentication to the request.
21
+ # @param [HttpRequest] The HttpRequest object to which authentication will
22
+ # be added.
23
+ def self.apply(http_request, url=nil, body=nil)
24
+ username = Configuration.hmac_auth_user_name
25
+
26
+ content_signature = ""
27
+ content_header = ""
28
+
29
+ now = DateTime.now.new_offset(0).to_time.strftime("%a, %d %b %Y %H:%M:%S GMT")
30
+
31
+ date_header = now
32
+
33
+ if body != nil
34
+ md5 = Digest::MD5.new
35
+ md5.update(body)
36
+
37
+ content_hash = md5.hexdigest
38
+ content_signature = "x-Content-MD5: #{content_hash}\n"
39
+ content_header = "x-Content-MD5 "
40
+ http_request.headers["x-Content-MD5"] = content_hash
41
+ end
42
+
43
+ http_request.headers["date"] = date_header
44
+
45
+ hmac_signature = HmacAuth.create_signature(date_header, content_signature, url, body)
46
+
47
+ joined = "username=\"#{username}\", algorithm=\"hmac-sha1\", headers=\"date #{content_header}request-line\", signature=\"#{hmac_signature}\""
48
+ header_value = "hmac #{joined}"
49
+ http_request.headers["Authorization"] = header_value
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,54 @@
1
+
2
+ require 'faraday/http_cache'
3
+
4
+ module MessageMediaLookups
5
+ # An implementation of HttpClient.
6
+ class FaradayClient < HttpClient
7
+ # The constructor.
8
+ def initialize(timeout: nil, cache: false,
9
+ max_retries: nil, retry_interval: nil)
10
+ @connection = Faraday.new do |faraday|
11
+ faraday.use Faraday::HttpCache, serializer: Marshal if cache
12
+ faraday.request :multipart
13
+ faraday.request :url_encoded
14
+ faraday.ssl[:ca_file] = Certifi.where
15
+ faraday.adapter Faraday.default_adapter
16
+ faraday.options[:params_encoder] = Faraday::FlatParamsEncoder
17
+ faraday.options[:open_timeout] = timeout if timeout
18
+ faraday.request :retry, max: max_retries, interval: if max_retries &&
19
+ retry_interval
20
+ retry_interval
21
+ end
22
+ end
23
+ end
24
+
25
+ # Method overridden from HttpClient.
26
+ def execute_as_string(http_request)
27
+ response = @connection.send(
28
+ http_request.http_method.downcase,
29
+ http_request.query_url
30
+ ) do |request|
31
+ request.headers = http_request.headers
32
+ request.body = http_request.parameters
33
+ end
34
+ convert_response(response)
35
+ end
36
+
37
+ # Method overridden from HttpClient.
38
+ def execute_as_binary(http_request)
39
+ response = @connection.send(
40
+ http_request.http_method.downcase,
41
+ http_request.query_url
42
+ ) do |request|
43
+ request.headers = http_request.headers
44
+ request.body = http_request.parameters
45
+ end
46
+ convert_response(response)
47
+ end
48
+
49
+ # Method overridden from HttpClient.
50
+ def convert_response(response)
51
+ HttpResponse.new(response.status, response.headers, response.body)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module MessageMediaLookups
3
+ # HttpCallBack allows defining callables for pre and post API calls.
4
+ class HttpCallBack
5
+ # A controller will call this method before making an HTTP Request.
6
+ # @param [HttpRequest] The HttpRequest object which the HttpClient
7
+ # will execute.
8
+ def on_before_request(_http_request)
9
+ raise NotImplementedError, 'This method needs
10
+ to be implemented in a child class.'
11
+ end
12
+
13
+ # A controller will call this method after making an HTTP Request.
14
+ # @param [HttpContext] The HttpContext of the API call.
15
+ def on_after_response(_http_context)
16
+ raise NotImplementedError, 'This method needs
17
+ to be implemented in a child class.'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,90 @@
1
+
2
+ module MessageMediaLookups
3
+ # An interface for the methods that an HTTP Client must implement.
4
+ #
5
+ # This class should not be instantiated but should be used as a base class
6
+ # for HTTP Client classes.
7
+ class HttpClient
8
+ # Execute an HttpRequest when the response is expected to be a string.
9
+ # @param [HttpRequest] The HttpRequest to be executed.
10
+ def execute_as_string(_http_request)
11
+ raise NotImplementedError, 'This method needs
12
+ to be implemented in a child class.'
13
+ end
14
+
15
+ # Execute an HttpRequest when the response is expected to be binary.
16
+ # @param [HttpRequest] The HttpRequest to be executed.
17
+ def execute_as_binary(_http_request)
18
+ raise NotImplementedError, 'This method needs
19
+ to be implemented in a child class.'
20
+ end
21
+
22
+ # Converts the HTTP Response from the client to an HttpResponse object.
23
+ # @param [Dynamic] The response object received from the client.
24
+ def convert_response(_response)
25
+ raise NotImplementedError, 'This method needs
26
+ to be implemented in a child class.'
27
+ end
28
+
29
+ # Get a GET HttpRequest object.
30
+ # @param [String] The URL to send the request to.
31
+ # @param [Hash, Optional] The headers for the HTTP Request.
32
+ def get(query_url,
33
+ headers: {})
34
+ HttpRequest.new(HttpMethodEnum::GET,
35
+ query_url,
36
+ headers: headers)
37
+ end
38
+
39
+ # Get a POST HttpRequest object.
40
+ # @param [String] The URL to send the request to.
41
+ # @param [Hash, Optional] The headers for the HTTP Request.
42
+ # @param [Hash, Optional] The parameters for the HTTP Request.
43
+ def post(query_url,
44
+ headers: {},
45
+ parameters: {})
46
+ HttpRequest.new(HttpMethodEnum::POST,
47
+ query_url,
48
+ headers: headers,
49
+ parameters: parameters)
50
+ end
51
+
52
+ # Get a PUT HttpRequest object.
53
+ # @param [String] The URL to send the request to.
54
+ # @param [Hash, Optional] The headers for the HTTP Request.
55
+ # @param [Hash, Optional] The parameters for the HTTP Request.
56
+ def put(query_url,
57
+ headers: {},
58
+ parameters: {})
59
+ HttpRequest.new(HttpMethodEnum::PUT,
60
+ query_url,
61
+ headers: headers,
62
+ parameters: parameters)
63
+ end
64
+
65
+ # Get a PATCH HttpRequest object.
66
+ # @param [String] The URL to send the request to.
67
+ # @param [Hash, Optional] The headers for the HTTP Request.
68
+ # @param [Hash, Optional] The parameters for the HTTP Request.
69
+ def patch(query_url,
70
+ headers: {},
71
+ parameters: {})
72
+ HttpRequest.new(HttpMethodEnum::PATCH,
73
+ query_url,
74
+ headers: headers,
75
+ parameters: parameters)
76
+ end
77
+
78
+ # Get a DELETE HttpRequest object.
79
+ # @param [String] The URL to send the request to.
80
+ # @param [Hash, Optional] The headers for the HTTP Request.
81
+ def delete(query_url,
82
+ headers: {},
83
+ parameters: {})
84
+ HttpRequest.new(HttpMethodEnum::DELETE,
85
+ query_url,
86
+ headers: headers,
87
+ parameters: parameters)
88
+ end
89
+ end
90
+ end