lib/nylas/http_client.rb in nylas-4.2.4 vs lib/nylas/http_client.rb in nylas-4.3.0

- old
+ new

@@ -1,8 +1,10 @@ +# frozen_string_literal: true + module Nylas # Plain HTTP client that can be used to interact with the Nylas API sans any type casting. - class HttpClient + class HttpClient # rubocop:disable Metrics/ClassLength HTTP_CODE_TO_EXCEPTIONS = { 400 => InvalidRequest, 402 => MessageRejected, 403 => AccessDenied, 404 => ResourceNotFound, @@ -13,10 +15,19 @@ 501 => EndpointNotYetImplemented, 502 => BadGateway, 503 => ServiceUnavailable }.freeze + ENDPOINT_TIMEOUTS = { + "/oauth/authorize" => 345, + "/messages/search" => 350, + "/threads/search" => 350, + "/delta" => 3650, + "/delta/longpoll" => 3650, + "/delta/streaming" => 3650 + }.freeze + include Logging attr_accessor :api_server, :service_domain attr_writer :default_headers attr_reader :access_token attr_reader :app_id @@ -32,10 +43,11 @@ def initialize(app_id:, app_secret:, access_token: nil, api_server: "https://api.nylas.com", service_domain: "api.nylas.com") unless api_server.include?("://") raise "When overriding the Nylas API server address, you must include https://" end + @api_server = api_server @access_token = access_token @app_secret = app_secret @app_id = app_id @service_domain = service_domain @@ -54,28 +66,37 @@ # @param headers [Hash] (Optional, defaults to {}) - Additional HTTP headers to include in the payload. # @param query [Hash] (Optional, defaults to {}) - Hash of names and values to include in the query # section of the URI fragment # @param payload [String,Hash] (Optional, defaults to nil) - Body to send with the request. # @return [Array Hash Stringn] + # rubocop:disable Metrics/MethodLength def execute(method:, path: nil, headers: {}, query: {}, payload: nil) - request = build_request(method: method, path: path, headers: headers, query: query, payload: payload) + timeout = ENDPOINT_TIMEOUTS.fetch(path, 230) + request = build_request( + method: method, + path: path, + headers: headers, + query: query, + payload: payload, + timeout: timeout + ) rest_client_execute(**request) do |response, _request, result| response = parse_response(response) handle_failed_response(result: result, response: response) response end end + # rubocop:enable Metrics/MethodLength inform_on :execute, level: :debug, also_log: { result: true, values: %i[method url path headers query payload] } - def build_request(method:, path: nil, headers: {}, query: {}, payload: nil) + def build_request(method:, path: nil, headers: {}, query: {}, payload: nil, timeout: nil) headers[:params] = query url ||= url_for_path(path) resulting_headers = default_headers.merge(headers) - { method: method, url: url, payload: payload, headers: resulting_headers } + { method: method, url: url, payload: payload, headers: resulting_headers, timeout: timeout } end - # rubocop:enable Metrics/ParameterLists # Syntactical sugar for making GET requests via the API. # @see #execute def get(path: nil, headers: {}, query: {}) execute(method: :get, path: path, query: query, headers: headers) @@ -96,22 +117,15 @@ # Syntactical sugar for making DELETE requests via the API. # @see #execute def delete(path: nil, payload: nil, headers: {}, query: {}) execute(method: :delete, path: path, headers: headers, query: query, payload: payload) end - # rubocop:enable Metrics/ParameterList - private def rest_client_execute(method:, url:, headers:, payload:, &block) - ::RestClient::Request.execute(method: method, url: url, payload: payload, - headers: headers, &block) - end - inform_on :rest_client_execute, level: :debug, - also_log: { result: true, values: %i[method url headers payload] } - def default_headers @default_headers ||= { "X-Nylas-API-Wrapper" => "ruby", + "X-Nylas-Client-Id" => @app_id, "User-Agent" => "Nylas Ruby SDK #{Nylas::VERSION} - #{RUBY_VERSION}", "Content-types" => "application/json" } end @@ -125,19 +139,30 @@ def url_for_path(path) protocol, domain = api_server.split("//") "#{protocol}//#{access_token}:@#{domain}#{path}" end - private def handle_failed_response(result:, response:) + private + + def rest_client_execute(method:, url:, headers:, payload:, timeout:, &block) + ::RestClient::Request.execute(method: method, url: url, payload: payload, + headers: headers, timeout: timeout, &block) + end + + inform_on :rest_client_execute, level: :debug, + also_log: { result: true, values: %i[method url headers payload] } + + def handle_failed_response(result:, response:) http_code = result.code.to_i handle_anticipated_failure_mode(http_code: http_code, response: response) raise UnexpectedResponse, result.msg if result.is_a?(Net::HTTPClientError) end - private def handle_anticipated_failure_mode(http_code:, response:) + def handle_anticipated_failure_mode(http_code:, response:) return if http_code == 200 return unless response.is_a?(Hash) + exception = HTTP_CODE_TO_EXCEPTIONS.fetch(http_code, APIError) raise exception.new(response[:type], response[:message], response.fetch(:server_error, nil)) end end end