Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
jsonapi-resources / lib / jsonapi / exceptions.rb
Size: Mime:
module JSONAPI
  module Exceptions
    class Error < RuntimeError; end

    class InternalServerError < Error
      attr_accessor :exception

      def initialize(exception)
        @exception = exception
      end

      def errors
        unless Rails.env.production?
          meta = Hash.new
          meta[:exception] = exception.message
          meta[:backtrace] = exception.backtrace
        end

        [JSONAPI::Error.new(code: JSONAPI::INTERNAL_SERVER_ERROR,
                            status: :internal_server_error,
                            title: I18n.t('jsonapi-resources.exceptions.internal_server_error.title', 
                                          default: 'Internal Server Error'),
                            detail: I18n.t('jsonapi-resources.exceptions.internal_server_error.detail', 
                                           default: 'Internal Server Error'),
                            meta: meta)]
      end
    end

    class InvalidResource < Error
      attr_accessor :resource
      def initialize(resource)
        @resource = resource
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_RESOURCE,
                            status: :bad_request,
                            title: I18n.t('jsonapi-resources.exceptions.invalid_resource.title', 
                                          default: 'Invalid resource'),
                            detail: I18n.t('jsonapi-resources.exceptions.invalid_resource.detail', 
                                           default: "#{resource} is not a valid resource.", resource: resource))]
      end
    end

    class RecordNotFound < Error
      attr_accessor :id
      def initialize(id)
        @id = id
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::RECORD_NOT_FOUND,
                            status: :not_found,
                            title: I18n.translate('jsonapi-resources.exceptions.record_not_found.title', 
                                                  default: 'Record not found'),
                            detail: I18n.translate('jsonapi-resources.exceptions.record_not_found.detail', 
                                                   default: "The record identified by #{id} could not be found.", id: id))]
      end
    end

    class UnsupportedMediaTypeError < Error
      attr_accessor :media_type
      def initialize(media_type)
        @media_type = media_type
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::UNSUPPORTED_MEDIA_TYPE,
                            status: :unsupported_media_type,
                            title: I18n.translate('jsonapi-resources.exceptions.unsupported_media_type.title', 
                                                  default: 'Unsupported media type'),
                            detail: I18n.translate('jsonapi-resources.exceptions.unsupported_media_type.detail',
                                                   default: "All requests that create or update must use the '#{JSONAPI::MEDIA_TYPE}' Content-Type. This request specified '#{media_type}'.",
                                                   needed_media_type: JSONAPI::MEDIA_TYPE,
                                                   media_type: media_type))]
      end
    end

    class HasManyRelationExists < Error
      attr_accessor :id
      def initialize(id)
        @id = id
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::RELATION_EXISTS,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.has_many_relation.title', 
                                                  default: 'Relation exists'),
                            detail: I18n.translate('jsonapi-resources.exceptions.has_many_relation.detail',
                                                   default: "The relation to #{id} already exists.",
                                                   id: id))]
      end
    end

    class ToManySetReplacementForbidden < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::FORBIDDEN,
                            status: :forbidden,
                            title: I18n.translate('jsonapi-resources.exceptions.to_many_set_replacement_forbidden.title', 
                                                  default: 'Complete replacement forbidden'),
                            detail: I18n.translate('jsonapi-resources.exceptions.to_many_set_replacement_forbidden.detail',
                                                   default: 'Complete replacement forbidden for this relationship'))]
      end
    end

    class InvalidFiltersSyntax < Error
      attr_accessor :filters
      def initialize(filters)
        @filters = filters
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_FILTERS_SYNTAX,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_filter_syntax.title',
                                                  default: 'Invalid filters syntax'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_filter_syntax.detail',
                                                   default: "#{filters} is not a valid syntax for filtering.",
                                                   filters: filters))]
      end
    end

    class FilterNotAllowed < Error
      attr_accessor :filter
      def initialize(filter)
        @filter = filter
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::FILTER_NOT_ALLOWED,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.filter_not_allowed.title',
                                                  default: 'Filter not allowed'),
                            detail: I18n.translate('jsonapi-resources.exceptions.filter_not_allowed.detail',
                                                   default: "#{filter} is not allowed.", filter: filter))]
      end
    end

    class InvalidFilterValue < Error
      attr_accessor :filter, :value
      def initialize(filter, value)
        @filter = filter
        @value = value
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_FILTER_VALUE,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_filter_value.title',
                                                  default: 'Invalid filter value'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_filter_value.detail',
                                                   default: "#{value} is not a valid value for #{filter}.",
                                                   value: value, filter: filter))]
      end
    end

    class InvalidFieldValue < Error
      attr_accessor :field, :value
      def initialize(field, value)
        @field = field
        @value = value
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_FIELD_VALUE,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_field_value.title',
                                                  default: 'Invalid field value'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_field_value.detail',
                                                   default: "#{value} is not a valid value for #{field}.",
                                                   value: value, field: field))]
      end
    end

    class InvalidFieldFormat < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_FIELD_FORMAT,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_field_format.title',
                                                  default: 'Invalid field format'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_field_format.detail',
                                                   default: 'Fields must specify a type.'))]
      end
    end

    class InvalidLinksObject < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_LINKS_OBJECT,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_links_object.title',
                                                  default: 'Invalid Links Object'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_links_object.detail',
                                                   default: 'Data is not a valid Links Object.'))]
      end
    end

    class TypeMismatch < Error
      attr_accessor :type
      def initialize(type)
        @type = type
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::TYPE_MISMATCH,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.type_mismatch.title',
                                                  default: 'Type Mismatch'),
                            detail: I18n.translate('jsonapi-resources.exceptions.type_mismatch.detail',
                                                   default: "#{type} is not a valid type for this operation.", type: type))]
      end
    end

    class InvalidField < Error
      attr_accessor :field, :type
      def initialize(type, field)
        @field = field
        @type = type
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_FIELD,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_field.title',
                                                  default: 'Invalid field'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_field.detail',
                                                   default: "#{field} is not a valid field for #{type}.",
                                                   field: field, type: type))]
      end
    end

    class InvalidInclude < Error
      attr_accessor :relationship, :resource
      def initialize(resource, relationship)
        @resource = resource
        @relationship = relationship
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_INCLUDE,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_include.title',
                                                  default: 'Invalid field'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_include.detail',
                                                   default: "#{relationship} is not a valid relationship of #{resource}",
                                                   relationship: relationship, resource: resource))]
      end
    end

    class InvalidSortCriteria < Error
      attr_accessor :sort_criteria, :resource
      def initialize(resource, sort_criteria)
        @resource = resource
        @sort_criteria = sort_criteria
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_SORT_CRITERIA,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_sort_criteria.title',
                                                  default: 'Invalid sort criteria'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_sort_criteria.detail',
                                                   default: "#{sort_criteria} is not a valid sort criteria for #{resource}",
                                                   sort_criteria: sort_criteria, resource: resource))]
      end
    end

    class ParametersNotAllowed < Error
      attr_accessor :params
      def initialize(params)
        @params = params
      end

      def errors
        params.collect do |param|
          JSONAPI::Error.new(code: JSONAPI::PARAM_NOT_ALLOWED,
                             status: :bad_request,
                             title: I18n.translate('jsonapi-resources.exceptions.parameters_not_allowed.title',
                                                   default: 'Param not allowed'),
                             detail: I18n.translate('jsonapi-resources.exceptions.parameters_not_allowed.detail',
                                                    default: "#{param} is not allowed.", param: param))

        end
      end
    end

    class ParameterMissing < Error
      attr_accessor :param
      def initialize(param)
        @param = param
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::PARAM_MISSING,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.parameter_missing.title',
                                                  default: 'Missing Parameter'),
                            detail: I18n.translate('jsonapi-resources.exceptions.parameter_missing.detail',
                                                   default: "The required parameter, #{param}, is missing.", param: param))]
      end
    end

    class CountMismatch < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::COUNT_MISMATCH,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.count_mismatch.title',
                                                  default: 'Count to key mismatch'),
                            detail: I18n.translate('jsonapi-resources.exceptions.count_mismatch.detail',
                                                   default: 'The resource collection does not contain the same number of objects as the number of keys.'))]
      end
    end

    class KeyNotIncludedInURL < Error
      attr_accessor :key
      def initialize(key)
        @key = key
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::KEY_NOT_INCLUDED_IN_URL,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.key_not_included_in_url.title',
                                                  default: 'Key is not included in URL'),
                            detail: I18n.translate('jsonapi-resources.exceptions.key_not_included_in_url.detail',
                                                   default: "The URL does not support the key #{key}",
                                                   key: key))]
      end
    end

    class MissingKey < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::KEY_ORDER_MISMATCH,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.missing_key.title',
                                                  default: 'A key is required'),
                            detail: I18n.translate('jsonapi-resources.exceptions.missing_key.detail',
                                                   default: 'The resource object does not contain a key.'))]
      end
    end

    class RecordLocked < Error
      attr_accessor :message
      def initialize(message)
        @message = message
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::LOCKED,
                            status: :locked,
                            title: I18n.translate('jsonapi-resources.exceptions.record_locked.title',
                                                  default: 'Locked resource'),
                            detail: "#{message}")]
      end
    end

    class ValidationErrors < Error
      attr_reader :error_messages, :error_metadata, :resource_relationships

      def initialize(resource)
        @error_messages = resource.model_error_messages
        @error_metadata = resource.validation_error_metadata
        @resource_relationships = resource.class._relationships.keys
        @key_formatter = JSONAPI.configuration.key_formatter
      end

      def format_key(key)
        @key_formatter.format(key)
      end

      def errors
        error_messages.flat_map do |attr_key, messages|
          messages.map { |message| json_api_error(attr_key, message) }
        end
      end

      private

      def json_api_error(attr_key, message)
        JSONAPI::Error.new(code: JSONAPI::VALIDATION_ERROR,
                           status: :unprocessable_entity,
                           title: message,
                           detail: "#{format_key(attr_key)} - #{message}",
                           source: { pointer: pointer(attr_key) },
                           meta: metadata_for(attr_key, message))
      end

      def metadata_for(attr_key, message)
        return if error_metadata.nil?
        error_metadata[attr_key] ?  error_metadata[attr_key][message] : nil
      end

      def pointer(attr_or_relationship_name)
        formatted_attr_or_relationship_name = format_key(attr_or_relationship_name)
        if resource_relationships.include?(attr_or_relationship_name)
          "/data/relationships/#{formatted_attr_or_relationship_name}"
        else
          "/data/attributes/#{formatted_attr_or_relationship_name}"
        end
      end
    end

    class SaveFailed < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::SAVE_FAILED,
                            status: :unprocessable_entity,
                            title: I18n.translate('jsonapi-resources.exceptions.save_failed.title',
                                                  default: 'Save failed or was cancelled'),
                            detail: I18n.translate('jsonapi-resources.exceptions.save_failed.detail',
                                                   default: 'Save failed or was cancelled'))]
      end
    end

    class InvalidPageObject < Error
      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_PAGE_OBJECT,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_page_object.title',
                                                  default: 'Invalid Page Object'),
                            detail: I18n.translate('jsonapi-resources.exceptions.invalid_page_object.detail',
                                                   default: 'Invalid Page Object.'))]
      end
    end

    class PageParametersNotAllowed < Error
      attr_accessor :params
      def initialize(params)
        @params = params
      end

      def errors
        params.collect do |param|
          JSONAPI::Error.new(code: JSONAPI::PARAM_NOT_ALLOWED,
                             status: :bad_request,
                             title: I18n.translate('jsonapi-resources.exceptions.page_parameters_not_allowed.title',
                                                   default: 'Page parameter not allowed'),
                             detail: I18n.translate('jsonapi-resources.exceptions.page_parameters_not_allowed.detail',
                                                    default: "#{param} is not an allowed page parameter.",
                                                    param: param))
        end
      end
    end

    class InvalidPageValue < Error
      attr_accessor :page, :value
      def initialize(page, value, msg = nil)
        @page = page
        @value = value
        @msg = msg || I18n.translate('jsonapi-resources.exceptions.invalid_page_value.detail',
                                     default: "#{value} is not a valid value for #{page} page parameter.",
                                     value: value, page: page)
      end

      def errors
        [JSONAPI::Error.new(code: JSONAPI::INVALID_PAGE_VALUE,
                            status: :bad_request,
                            title: I18n.translate('jsonapi-resources.exceptions.invalid_page_value.title',
                                                  default: 'Invalid page value'),
                            detail: @msg)]
      end
    end
  end
end