diff --git a/lib/contentstack/api.rb b/lib/contentstack/api.rb index a5ce74e..d55da61 100644 --- a/lib/contentstack/api.rb +++ b/lib/contentstack/api.rb @@ -7,7 +7,7 @@ module Contentstack class API using Utility - def self.init_api(api_key, delivery_token, environment, host, branch, live_preview) + def self.init_api(api_key, delivery_token, environment, host, branch, live_preview, proxy, retry_options) @host = host @api_version = '/v3' @environment = environment @@ -16,6 +16,11 @@ def self.init_api(api_key, delivery_token, environment, host, branch, live_previ @branch = branch @headers = {environment: @environment} @live_preview = live_preview + @proxy_details = proxy + @timeout = retry_options["timeout"] + @retryDelay = retry_options["retryDelay"] + @retryLimit = retry_options["retryLimit"] + @errorRetry = retry_options["errorRetry"] end def self.live_preview_query(query= {}) @@ -29,7 +34,7 @@ def self.fetch_content_types(uid="") else path = "/content_types" end - send_request(path, {}) + fetch_retry(path, {}) end def self.fetch_entries(content_type, query) @@ -38,7 +43,7 @@ def self.fetch_entries(content_type, query) send_preview_request(path, query) else path = "/content_types/#{content_type}/entries" - send_request(path, query) + fetch_retry(path, query) end end @@ -48,22 +53,37 @@ def self.fetch_entry(content_type, entry_uid, query) send_preview_request(path, query) else path = "/content_types/#{content_type}/entries/#{entry_uid}" - send_request(path, query) + fetch_retry(path, query) end end def self.get_assets(asset_uid=nil) path = "/assets" path += "/#{asset_uid}" if !asset_uid.nil? - send_request(path) + fetch_retry(path) end def self.get_sync_items(query) path = "/stacks/sync" - send_request(path, query) + fetch_retry(path, query) end private + def self.fetch_retry(path, query=nil, count=0) + response = send_request(path, query) + if @errorRetry.include?(response["status_code"].to_i) + if count < @retryLimit + retryDelay_in_seconds = @retryDelay / 1000 #converting retry_delay from milliseconds into seconds + sleep(retryDelay_in_seconds.to_i) #sleep method requires time in seconds as parameter + response = fetch_retry(path, query, (count + 1)) + else + raise Contentstack::Error.new(response) #Retry Limit exceeded + end + else + response + end + end + def self.send_request(path, q=nil) q ||= {} @@ -75,12 +95,44 @@ def self.send_request(path, q=nil) "api_key" => @api_key, "access_token"=> @access_token, "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", - "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}" + "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", + "read_timeout" => @timeout } if !@branch.nil? && !@branch.empty? params["branch"] = @branch end - ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", params).read) + + begin + if @proxy_details.empty? + ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", params).read) + elsif @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].present? && @proxy_details[:password].present? + proxy_uri = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/") + proxy_username = @proxy_details[:username] + proxy_password = @proxy_details[:password] + + if !@branch.nil? && !@branch.empty? + ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", :proxy_http_basic_authentication => [proxy_uri, proxy_username, proxy_password], "api_key" => @api_key, "access_token"=> @access_token, "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout, "branch" => @branch).read) + else + ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", :proxy_http_basic_authentication => [proxy_uri, proxy_username, proxy_password], "api_key" => @api_key, "access_token"=> @access_token, "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout).read) + end + elsif @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].empty? && @proxy_details[:password].empty? + proxy_uri = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/") + + if !@branch.nil? && !@branch.empty? + ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", "proxy" => proxy_uri, "api_key" => @api_key, "access_token"=> @access_token, "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout, "branch" => @branch).read) + else + ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", "proxy" => proxy_uri, "api_key" => @api_key, "access_token"=> @access_token, "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout).read) + end + end + rescue OpenURI::HTTPError => error + response = error.io + #response.status + # => ["503", "Service Unavailable"] + error_response = JSON.parse(response.string) + error_status = {"status_code" => response.status[0], "status_message" => response.status[1]} + error = error_response.merge(error_status) + raise Contentstack::Error.new(error.to_s) + end end def self.send_preview_request(path, q=nil) @@ -94,12 +146,43 @@ def self.send_preview_request(path, q=nil) "api_key" => @api_key, "authorization" => @live_preview[:management_token], "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", - "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}" + "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", + "read_timeout" => @timeout } if !@branch.nil? && !@branch.empty? params["branch"] = @branch end - ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}",params).read) + begin + if @proxy_details.empty? + ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}",params).read) + elsif @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].present? && @proxy_details[:password].present? + proxy_uri = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/") + proxy_username = @proxy_details[:username] + proxy_password = @proxy_details[:password] + + if !@branch.nil? && !@branch.empty? + ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}", :proxy_http_basic_authentication => [proxy_uri, proxy_username, proxy_password], "api_key" => @api_key, "authorization" => @live_preview[:management_token], "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout, "branch" => @branch).read) + else + ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}", :proxy_http_basic_authentication => [proxy_uri, proxy_username, proxy_password], "api_key" => @api_key, "authorization" => @live_preview[:management_token], "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout).read) + end + elsif @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].empty? && @proxy_details[:password].empty? + proxy_uri = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/") + + if !@branch.nil? && !@branch.empty? + ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}", "proxy" => proxy_uri, "api_key" => @api_key, "authorization" => @live_preview[:management_token], "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout, "branch" => @branch).read) + else + ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}", "proxy" => proxy_uri, "api_key" => @api_key, "authorization" => @live_preview[:management_token], "user_agent"=> "ruby-sdk/#{Contentstack::VERSION}", "x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}", "read_timeout" => @timeout).read) + end + end + rescue OpenURI::HTTPError => error + response = error.io + #response.status + # => ["503", "Service Unavailable"] + error_response = JSON.parse(response.string) + error_status = {"status_code" => response.status[0], "status_message" => response.status[1]} + error = error_response.merge(error_status) + raise Contentstack::Error.new(error.to_s) + end end end end diff --git a/lib/contentstack/client.rb b/lib/contentstack/client.rb index dcabe86..11d9af3 100644 --- a/lib/contentstack/client.rb +++ b/lib/contentstack/client.rb @@ -3,17 +3,37 @@ require 'contentstack/asset_collection' require 'contentstack/sync_result' require 'util' +require 'contentstack/error' module Contentstack class Client using Utility attr_reader :region, :host # Initialize "Contentstack" Client instance def initialize(api_key, delivery_token, environment, options={}) + raise Contentstack::Error.new("Api Key is not valid") if api_key.class != String + raise Contentstack::Error.new("Api Key Field Should not be Empty") if api_key.empty? + raise Contentstack::Error.new("Delivery Token is not valid") if delivery_token.class != String + raise Contentstack::Error.new("Delivery Token Field Should not be Empty") if delivery_token.empty? + raise Contentstack::Error.new("Envirnoment Field is not valid") if environment.class != String + raise Contentstack::Error.new("Envirnoment Field Should not be Empty") if environment.empty? @region = options[:region].nil? ? Contentstack::Region::US : options[:region] @host = options[:host].nil? ? get_default_region_hosts(@region) : options[:host] @live_preview = !options.key?(:live_preview) ? {} : options[:live_preview] @branch = options[:branch].nil? ? "" : options[:branch] - API.init_api(api_key, delivery_token, environment, @host, @branch, @live_preview) + @proxy_details = options[:proxy].nil? ? "" : options[:proxy] + @timeout = options[:timeout].nil? ? 3000 : options[:timeout] + @retryDelay = options[:retryDelay].nil? ? 3000 : options[:retryDelay] + @retryLimit = options[:retryLimit].nil? ? 5 : options[:retryLimit] + @errorRetry = options[:errorRetry].nil? ? [408, 429] : options[:errorRetry] + retry_options = { + "timeout" => @timeout.to_s, + "retryDelay"=> @retryDelay, + "retryLimit"=> @retryLimit, + "errorRetry" => @errorRetry + } + raise Contentstack::Error.new("Proxy URL Should not be Empty") if @proxy_details.present? && @proxy_details[:url].empty? + raise Contentstack::Error.new("Proxy Port Should not be Empty") if @proxy_details.present? && @proxy_details[:port].empty? + API.init_api(api_key, delivery_token, environment, @host, @branch, @live_preview, @proxy_details, retry_options) end def content_types diff --git a/lib/contentstack/query.rb b/lib/contentstack/query.rb index 7b8361e..85d9389 100644 --- a/lib/contentstack/query.rb +++ b/lib/contentstack/query.rb @@ -249,10 +249,14 @@ def not_equal_to(field_uid, value) # @param [String] field_uid UID of the field for which query should be executed # @param [String] values The possible values for the key's object # - # Example + # Example 1 - Array Equals Operator Within Group # @query = @stack.content_type('category').query # @query.contained_in("title", ["Electronics", "Apparel"]) # + # Example 2 - Array Equals Operator Within Modular Blocks + # @query = @stack.content_type('category').query + # @query.contained_in("additional_info.deals.deal_name", ["Christmas Deal", "Summer Deal"]) + # # @return [Contentstack::Query] def contained_in(field_uid, values) add_query_hash({:"#{field_uid}" => {"$in" => values}}) @@ -264,10 +268,14 @@ def contained_in(field_uid, values) # @param [String] field_uid UID of the field for which query should be executed # @param [String] values The possible values for the key's object # - # Example + # Example 1 - Array Not-equals Operator Within Group # @query = @stack.content_type('category').query # @query.not_contained_in("title", ["Electronics", "Apparel"]) # + # Example 2 - Array Not-equals Operator Within Modular Blocks + # @query = @stack.content_type('category').query + # @query.not_contained_in("additional_info.deals.deal_name", ["Christmas Deal", "Summer Deal"]) + # # @return [Contentstack::Query] def not_contained_in(field_uid, values) add_query_hash({:"#{field_uid}" => {"$nin" => values}}) @@ -377,6 +385,7 @@ def descending(field_uid) # @param [String] code The locale code of the entry # # Example + # Change language method # @query = @stack.content_type('category').query # @query.locale('en-us') #