class TLAW::Endpoint
This class does all the hard work: actually calling some HTTP API
and processing responses.
Each real API
endpoint is this class descendant, defining its own params and response processors. On each call small instance of this class is created, {#call}-ed and dies as you don't need it anymore.
Typically, you will neither create nor use endpoint descendants or instances directly:
-
endpoint class definition is performed through {DSL} helpers,
-
and then, containing namespace obtains `.<current_endpoint_name>()` method, which is (almost) everything you need to know.
Attributes
Public Class Methods
@private
# File lib/tlaw/endpoint.rb, line 44 def construct_template tpl = if query_string_params.empty? base_url else joiner = base_url.include?('?') ? '&' : '?' "#{base_url}{#{joiner}#{query_string_params.join(',')}}" end Addressable::Template.new(tpl) end
Inspects endpoint class prettily.
Example:
“`ruby some_api.some_namespace.endpoints # => <SomeApi::SomeNamespace::MyEndpoint call-sequence: my_endpoint(param1, param2: nil), docs: .describe> “`
# File lib/tlaw/endpoint.rb, line 31 def inspect "#<#{name || '(unnamed endpoint class)'}:" \ " call-sequence: #{symbol}(#{param_set.to_code}); docs: .describe>" end
Creates endpoint class (or descendant) instance. Typically, you never use it directly.
Params defined in parent namespace are passed here.
TLAW::APIPath::new
# File lib/tlaw/endpoint.rb, line 78 def initialize(**parent_params) super @client = Faraday.new do |faraday| faraday.use FaradayMiddleware::FollowRedirects faraday.adapter Faraday.default_adapter end @url_template = self.class.construct_template end
@private
# File lib/tlaw/endpoint.rb, line 55 def parse(body) if xml Crack::XML.parse(body) else JSON.parse(body) end.derp { |response| response_processor.process(response) } end
@private
# File lib/tlaw/endpoint.rb, line 37 def to_code "def #{to_method_definition}\n" \ " child(:#{symbol}, Endpoint).call({#{param_set.to_hash_code}})\n" \ 'end' end
Private Class Methods
# File lib/tlaw/endpoint.rb, line 65 def query_string_params param_set.all_params.values.map(&:field).map(&:to_s) - Addressable::Template.new(base_url).keys end
Public Instance Methods
Does the real call to the API
, with all params passed to this method and to parent namespace.
Typically, you don't use it directly, that's what called when you do `some_namespace.endpoint_name(**params)`.
@return [Hash,Array] Parsed, flattened and post-processed response
body.
# File lib/tlaw/endpoint.rb, line 96 def call(**params) url = construct_url(**full_params(params)) @client.get(url) .tap { |response| guard_errors!(response) } .derp { |response| self.class.parse(response.body) } rescue API::Error raise # Not catching in the next block rescue => e raise unless url raise API::Error, "#{e.class} at #{url}: #{e.message}" end
Private Instance Methods
# File lib/tlaw/endpoint.rb, line 129 def construct_url(**params) url_params = self.class.param_set.process(**params) @url_template .expand(url_params).normalize.to_s .split('?', 2).derp { |url, param| [url.gsub('%2F', '/'), param] } .compact.join('?') end
# File lib/tlaw/endpoint.rb, line 113 def full_params(**params) @parent_params.merge(params.reject { |_, v| v.nil? }) end
# File lib/tlaw/endpoint.rb, line 117 def guard_errors!(response) # TODO: follow redirects return response if (200...400).cover?(response.status) body = JSON.parse(response.body) rescue nil message = body && (body['message'] || body['error']) fail API::Error, "HTTP #{response.status} at #{response.env[:url]}" + (message ? ': ' + message : '') end