# encoding: utf-8 require 'json' require_relative '../error' module Github # Raised when GitHub returns any of the HTTP status codes module Error class ServiceError < GithubError # Add http status code method to error type # # @param [Integer] code # the status code # # @api public def self.http_status_code(code) define_method(:http_status_code) { code } end # A mapping of status codes and error types # # @return [Hash[Integer, Object]] # # @api public def self.error_mapping @error_mapping ||= Hash[ descendants.map do |klass| [klass.new({}).http_status_code, klass] end ] end MIN_BODY_LENGTH = 2 # Crate a ServiceError # # @param [Hash[Symbol]] response # # @api public def initialize(response) @headers = response[:response_headers] @body = response[:body] @status = response[:status] @response_headers = @headers @response_message = @body super(create_message(response)) end # Expose response payload as JSON object if possible # # @return [Hash[Symbol]|String] # # @api public def data @data ||= decode_data(@body) end # Stores error message(s) returned in response body # # @return [Array[Hash[Symbol]]] # the array of hash error objects # # @api public def error_messages @error_messages ||= begin data[:errors] ? data[:errors] : [data] end end private # Create full error message # # @param [Hash[Symbol]] response # the http response # # @return [String] # the error message # # @api private def create_message(response) return if response.nil? message = "#{response[:method].to_s.upcase} " message << "#{response[:url]}: " message << "#{@status} - #{format_response}" message end # Decode body information if in JSON format # # @param [String] body # the response body # # @api private def decode_data(body) if body.respond_to?(:to_str) && body.length >= MIN_BODY_LENGTH && @headers[:content_type] =~ /json/ JSON.parse(body, symbolize_names: true) else body end end # Read response body and convert to human friendly format # # @return [String] # # @api private def format_response return '' if data.nil? || data.empty? case data when Hash message = data[:message] ? data[:message] : ' ' docs = data[:documentation_url] error = create_error_summary message << error if error message << "\nSee: #{docs}" if docs message when String data end end # Create error summary from response body # # @return [String] # # @api private def create_error_summary if data[:error] "\nError: #{data[:error]}" elsif data[:errors] message = "\nErrors:\n" message << data[:errors].map do |error| case error when Hash "Error: #{error.map { |k, v| "#{k}: #{v}" }.join(', ')}" else "Error: #{error}" end end.join("\n") end end end # ServiceError # Raised when Github returns the HTTP status code 400 class BadRequest < ServiceError http_status_code 400 end # Raised when GitHub returns the HTTP status code 401 class Unauthorized < ServiceError http_status_code 401 end # Raised when Github returns the HTTP status code 403 class Forbidden < ServiceError http_status_code 403 end # Raised when Github returns the HTTP status code 404 class NotFound < ServiceError http_status_code 404 end # Raised when Github returns the HTTP status code 405 class MethodNotAllowed < ServiceError http_status_code 405 end # Raised when Github returns the HTTP status code 406 class NotAcceptable < ServiceError http_status_code 406 end # Raised when GitHub returns the HTTP status code 409 class Conflict < ServiceError http_status_code 409 end # Raised when GitHub returns the HTTP status code 414 class UnsupportedMediaType < ServiceError http_status_code 414 end # Raised when GitHub returns the HTTP status code 422 class UnprocessableEntity < ServiceError http_status_code 422 end # Raised when GitHub returns the HTTP status code 451 class UnavailableForLegalReasons < ServiceError http_status_code 451 end # Raised when Github returns the HTTP status code 500 class InternalServerError < ServiceError http_status_code 500 end # Raised when Github returns the HTTP status code 501 class NotImplemented < ServiceError http_status_code 501 end # Raised when Github returns the HTTP status code 502 class BadGateway < ServiceError http_status_code 502 end # Raised when GitHub returns the HTTP status code 503 class ServiceUnavailable < ServiceError http_status_code 503 end end # Error end # Github