module Jekyll::Algolia::ErrorHandler
Catch API errors and display messages
Public Class Methods
Public: Parses an Algolia
error message into a hash of its content
message - The raw message as returned by the API
Returns a hash of all parts of the message, to be more easily consumed by our error matchers
# File lib/jekyll/algolia/error_handler.rb, line 75 def self.error_hash(message) message = message.delete("\n") # Ex: Cannot PUT to https://appid.algolia.net/1/indexes/index_name/settings: # {"message":"Invalid Application-ID or API key","status":403} (403) regex = VerEx.new do find 'Cannot ' capture('verb') { word } find ' to ' capture('scheme') { word } find '://' capture('application_id') { word } anything_but '/' find '/' capture('api_version') { digit } find '/' capture('api_section') { word } find '/' capture('index_name') do anything_but('/') end find '/' capture do capture('api_action') { word } maybe '?' capture('query_parameters') do anything_but(':') end end find ': ' capture('json') do find '{' anything_but('}') find '}' end find ' (' capture('http_error') { word } find ')' end matches = regex.match(message) return false unless matches # Convert matches to a hash hash = {} matches.names.each do |name| hash[name] = matches[name] end hash['api_version'] = hash['api_version'].to_i hash['http_error'] = hash['http_error'].to_i # Merging the JSON key directly in the answer hash = hash.merge(JSON.parse(hash['json'])) hash.delete('json') # Merging the query parameters in the answer CGI.parse(hash['query_parameters']).each do |key, values| hash[key] = values[0] end hash.delete('query_parameters') hash end
Public: Will identify the error and return its internal name
error - The caught error context - A hash of additional information that can be passed from the code intercepting the user
It will parse in order all potential known issues until it finds one that matches. Returns false if no match, or a hash of :name and :details further identifying the issue.
# File lib/jekyll/algolia/error_handler.rb, line 46 def self.identify(error, context = {}) known_errors = %w[ unknown_application_id invalid_credentials record_too_big_api too_many_records unknown_setting invalid_index_name ] # Checking the errors against our known list known_errors.each do |potential_error| error_check = send("#{potential_error}?", error, context) next if error_check == false return { name: potential_error, details: error_check } end false end
Public: Check if the credentials are working
_context - Not used
Application ID and API key submitted don't match any credentials known
# File lib/jekyll/algolia/error_handler.rb, line 164 def self.invalid_credentials?(error, _context = {}) details = error_hash(error.message) return false if details == false if details['message'] != 'Invalid Application-ID or API key' return false end { 'application_id' => details['application_id'], 'index_name' => Configurator.index_name, 'index_object_ids_name' => Configurator.index_object_ids_name } end
Public: Check if the index name is invalid
Some characters are forbidden in index names
# File lib/jekyll/algolia/error_handler.rb, line 232 def self.invalid_index_name?(error, _context = {}) details = error_hash(error.message) return false if details == false message = details['message'] return false if message !~ /^indexName is not valid.*/ { 'index_name' => Configurator.index_name } end
Public: Check if the sent records are not too big
context - list of records sent in the batch
One of the sent record is too big and has been rejected by the API. This should not happen as we proactively check for record size before pushing them. If it still happens it means that the value set in max_record_size is not matching the value in the plan.
# File lib/jekyll/algolia/error_handler.rb, line 187 def self.record_too_big_api?(error, _context = {}) details = error_hash(error.message) return false if details == false message = details['message'] return false if message !~ /^Record .* is too big .*/ record_size, = /.*size=(.*) bytes.*/.match(message).captures record_size_readable = Filesize.from("#{record_size}B").to_s('Kb') max_record_size = Configurator.algolia('max_record_size') { 'record_size' => record_size_readable, 'max_record_size' => max_record_size } end
Public: Stop the execution of the plugin and display if possible a human-readable error message
error - The caught error context - A hash of values that will be passed from where the error happened to the display
# File lib/jekyll/algolia/error_handler.rb, line 19 def self.stop(error, context = {}) Logger.verbose("E:[jekyll-algolia] Raw error: #{error}") identified_error = identify(error, context) if identified_error == false Logger.log('E:[jekyll-algolia] Error:') Logger.log("E:#{error}") else Logger.known_message( identified_error[:name], identified_error[:details] ) end exit 1 end
Public: Check if the application has too many records
We're trying to push too many records and it goes over quota
# File lib/jekyll/algolia/error_handler.rb, line 247 def self.too_many_records?(error, _context = {}) details = error_hash(error.message) return false if details == false message = details['message'] return false if message !~ /^Record quota exceeded.*/ {} end
Public: Check if the application id is available
_context - Not used
If the call to the cluster fails, chances are that the application ID is invalid. As we cannot actually contact the server, the error is raw and does not follow our error spec
# File lib/jekyll/algolia/error_handler.rb, line 146 def self.unknown_application_id?(error, _context = {}) message = error.message return false if message !~ /^Cannot reach any host/ matches = /.*\((.*)\.algolia.net.*/.match(message) # The API will browse on APP_ID-dsn, but push/delete on APP_ID only # We need to catch both potential errors app_id = matches[1].gsub(/-dsn$/, '') { 'application_id' => app_id } end
Public: Check if one of the index settings is invalid
context - The settings passed to update the index
The API will block any call that tries to update a setting value that is not available. We'll tell the user which one so they can fix their issue.
# File lib/jekyll/algolia/error_handler.rb, line 211 def self.unknown_setting?(error, context = {}) details = error_hash(error.message) return false if details == false message = details['message'] return false if message !~ /^Invalid object attributes.*/ # Getting the unknown setting name regex = /^Invalid object attributes: (.*) near line.*/ setting_name, = regex.match(message).captures setting_value = context[:settings][setting_name] { 'setting_name' => setting_name, 'setting_value' => setting_value } end