apill 2.9.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/apill/errors/invalid_api_request_error.rb +9 -7
- data/lib/apill/errors/invalid_subdomain_error.rb +9 -7
- data/lib/apill/parameters/filter.rb +23 -0
- data/lib/apill/parameters/index.rb +17 -0
- data/lib/apill/parameters/page.rb +22 -0
- data/lib/apill/parameters/sort.rb +27 -0
- data/lib/apill/resource/model.rb +42 -0
- data/lib/apill/resource/processors/filtering.rb +63 -0
- data/lib/apill/resource/processors/indexing.rb +32 -0
- data/lib/apill/resource/processors/paging.rb +39 -0
- data/lib/apill/resource/processors/sorting.rb +35 -0
- data/lib/apill/resource.rb +68 -0
- data/lib/apill/version.rb +1 -1
- data/lib/apill.rb +1 -6
- data/spec/apill/errors/invalid_api_request_error_spec.rb +8 -17
- data/spec/apill/errors/invalid_subdomain_error_spec.rb +6 -15
- data/spec/apill/invalid_subdomain_response_spec.rb +31 -35
- data/spec/apill/middleware/api_request_spec.rb +47 -54
- data/spec/apill/resource/model_spec.rb +66 -0
- data/spec/apill/resource/processors/filtering_spec.rb +84 -0
- data/spec/apill/resource/processors/indexing_spec.rb +11 -0
- data/spec/apill/resource/processors/paging_spec.rb +54 -0
- data/spec/apill/resource/processors/sorting_spec.rb +74 -0
- metadata +24 -22
- data/lib/apill/mixins/indexable.rb +0 -49
- data/lib/apill/mixins/pageable.rb +0 -51
- data/lib/apill/mixins/queryable.rb +0 -86
- data/lib/apill/mixins/sortable.rb +0 -48
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c68aa89f529dc07063d53a0f2e53e210b606c1bb
         | 
| 4 | 
            +
              data.tar.gz: 6fc4b20a268b92b45d8e2e3f0b6ae195b118827d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 02544a5f552ca8205ccd6aff687b60460f001c06b49db580ebfc9ad2cc841e5af9af65440af2494d1ba3f4baf6c56b002d68ce1afc720b90c5b0192d62d7c509
         | 
| 7 | 
            +
              data.tar.gz: 9ac237ebc9b635993885a286f8b22353c98c655efc68fde7c50056dba9cbc332298465e328bcc80c8cf23cc6a0f44eab59c21aa381943c06a43c54993fe8a4a5
         | 
| @@ -2,25 +2,27 @@ require 'human_error' | |
| 2 2 |  | 
| 3 3 | 
             
            module  Apill
         | 
| 4 4 | 
             
            module  Errors
         | 
| 5 | 
            -
            class   InvalidApiRequestError <  | 
| 5 | 
            +
            class   InvalidApiRequestError < RuntimeError
         | 
| 6 | 
            +
              include HumanError::Error
         | 
| 7 | 
            +
             | 
| 6 8 | 
             
              attr_accessor :accept_header
         | 
| 7 9 |  | 
| 8 10 | 
             
              def http_status
         | 
| 9 11 | 
             
                400
         | 
| 10 12 | 
             
              end
         | 
| 11 13 |  | 
| 12 | 
            -
              def  | 
| 14 | 
            +
              def title
         | 
| 15 | 
            +
                'Invalid API Request'
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def detail
         | 
| 13 19 | 
             
                'The accept header that you passed in the request cannot be parsed, ' \
         | 
| 14 20 | 
             
                'please refer to the documentation to verify.'
         | 
| 15 21 | 
             
              end
         | 
| 16 22 |  | 
| 17 | 
            -
              def  | 
| 23 | 
            +
              def source
         | 
| 18 24 | 
             
                { accept_header: accept_header }
         | 
| 19 25 | 
             
              end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              def friendly_message
         | 
| 22 | 
            -
                "Sorry! We couldn't understand what you were trying to ask us to do."
         | 
| 23 | 
            -
              end
         | 
| 24 26 | 
             
            end
         | 
| 25 27 | 
             
            end
         | 
| 26 28 | 
             
            end
         | 
| @@ -2,25 +2,27 @@ require 'human_error' | |
| 2 2 |  | 
| 3 3 | 
             
            module  Apill
         | 
| 4 4 | 
             
            module  Errors
         | 
| 5 | 
            -
            class   InvalidSubdomainError <  | 
| 5 | 
            +
            class   InvalidSubdomainError < RuntimeError
         | 
| 6 | 
            +
              include HumanError::Error
         | 
| 7 | 
            +
             | 
| 6 8 | 
             
              attr_accessor :http_host
         | 
| 7 9 |  | 
| 8 10 | 
             
              def http_status
         | 
| 9 11 | 
             
                404
         | 
| 10 12 | 
             
              end
         | 
| 11 13 |  | 
| 12 | 
            -
              def  | 
| 14 | 
            +
              def title
         | 
| 15 | 
            +
                'Invalid Subdomain'
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def detail
         | 
| 13 19 | 
             
                'The resource you attempted to access is either not authorized for the ' \
         | 
| 14 20 | 
             
                'authenticated user or does not exist.'
         | 
| 15 21 | 
             
              end
         | 
| 16 22 |  | 
| 17 | 
            -
              def  | 
| 23 | 
            +
              def source
         | 
| 18 24 | 
             
                { http_host: http_host }
         | 
| 19 25 | 
             
              end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              def friendly_message
         | 
| 22 | 
            -
                'Sorry! The resource you tried to access does not exist.'
         | 
| 23 | 
            -
              end
         | 
| 24 26 | 
             
            end
         | 
| 25 27 | 
             
            end
         | 
| 26 28 | 
             
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module  Apill
         | 
| 2 | 
            +
            class   Parameters
         | 
| 3 | 
            +
            class   Filter
         | 
| 4 | 
            +
              attr_accessor :raw_parameters
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def initialize(raw_parameters)
         | 
| 7 | 
            +
                self.raw_parameters = raw_parameters
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def each_with_object(memoized)
         | 
| 11 | 
            +
                raw_parameters.each do |raw_parameter|
         | 
| 12 | 
            +
                  next if raw_parameter[0] == 'query' ||
         | 
| 13 | 
            +
                          raw_parameter[1] == '' ||
         | 
| 14 | 
            +
                          raw_parameter[1].nil?
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  memoized = yield raw_parameter[0], raw_parameter[1], memoized
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                memoized
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module  Apill
         | 
| 2 | 
            +
            class   Parameters
         | 
| 3 | 
            +
            class   Index
         | 
| 4 | 
            +
              DEFAULT_QUERY = '*'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              attr_accessor :raw_parameters
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def initialize(raw_parameters)
         | 
| 9 | 
            +
                self.raw_parameters = raw_parameters
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def query
         | 
| 13 | 
            +
                raw_parameters['query'] || raw_parameters['q']
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module  Apill
         | 
| 2 | 
            +
            class   Parameters
         | 
| 3 | 
            +
            class   Page
         | 
| 4 | 
            +
              DEFAULT_STARTING_PAGE = 1
         | 
| 5 | 
            +
              DEFAULT_PAGE_SIZE     = 25
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              attr_accessor :raw_parameters
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def initialize(raw_parameters)
         | 
| 10 | 
            +
                self.raw_parameters = raw_parameters
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def page_number
         | 
| 14 | 
            +
                raw_parameters['number'] || DEFAULT_STARTING_PAGE
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def per_page
         | 
| 18 | 
            +
                raw_parameters['size'] || DEFAULT_PAGE_SIZE
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            module  Apill
         | 
| 2 | 
            +
            class   Parameters
         | 
| 3 | 
            +
            class   Sort
         | 
| 4 | 
            +
              DESCENDING_PREFIX = '-'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              attr_accessor :raw_parameters
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def initialize(raw_parameters)
         | 
| 9 | 
            +
                self.raw_parameters = raw_parameters ? raw_parameters.split(',') : ['-created_at']
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def to_h
         | 
| 13 | 
            +
                @to_h ||= Hash[to_a]
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def to_a
         | 
| 17 | 
            +
                @to_a ||= raw_parameters.map do |raw_parameter|
         | 
| 18 | 
            +
                  if raw_parameter.start_with?(DESCENDING_PREFIX)
         | 
| 19 | 
            +
                    [raw_parameter[1..-1], 'desc']
         | 
| 20 | 
            +
                  else
         | 
| 21 | 
            +
                    [raw_parameter, 'asc']
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
            end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            require 'apill/resource/processors/filtering'
         | 
| 2 | 
            +
            require 'apill/resource/processors/sorting'
         | 
| 3 | 
            +
            require 'apill/resource/processors/paging'
         | 
| 4 | 
            +
            require 'apill/resource/processors/indexing'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module  Apill
         | 
| 7 | 
            +
            module  Resource
         | 
| 8 | 
            +
            class   Model
         | 
| 9 | 
            +
              DEFAULT_PROCESSORS = %w{filtering sorting paging indexing}
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              attr_accessor :resource,
         | 
| 12 | 
            +
                            :parameters,
         | 
| 13 | 
            +
                            :processors
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def initialize(resource:, parameters:, **options)
         | 
| 16 | 
            +
                self.resource   = resource
         | 
| 17 | 
            +
                self.parameters = parameters
         | 
| 18 | 
            +
                self.processors = options.fetch(:processors, DEFAULT_PROCESSORS)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def processed
         | 
| 22 | 
            +
                @processed ||= \
         | 
| 23 | 
            +
                  processors.inject(resource) do |processed_resource, processor|
         | 
| 24 | 
            +
                    processor.processed(processed_resource, parameters)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def meta
         | 
| 29 | 
            +
                @meta ||= \
         | 
| 30 | 
            +
                  processors.inject({}) do |metadata, processor|
         | 
| 31 | 
            +
                    metadata.merge processor.meta(processed, parameters)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              def processors=(other)
         | 
| 36 | 
            +
                @processors = other.map do |processor|
         | 
| 37 | 
            +
                  Object.const_get "::Apill::Resource::Processors::#{processor.capitalize}"
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
            end
         | 
| 42 | 
            +
            end
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            require 'apill/parameters/filter'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Apill
         | 
| 4 | 
            +
            module Resource
         | 
| 5 | 
            +
            module Processors
         | 
| 6 | 
            +
            class  Filtering
         | 
| 7 | 
            +
              attr_accessor :resource,
         | 
| 8 | 
            +
                            :parameters
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def initialize(resource, parameters = {})
         | 
| 11 | 
            +
                self.resource   = resource
         | 
| 12 | 
            +
                self.parameters = Parameters::Filter.new(parameters['filter'] || {})
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def self.processed(*attrs)
         | 
| 16 | 
            +
                new(*attrs).processed
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def self.meta(*_attrs)
         | 
| 20 | 
            +
                {}
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def processed
         | 
| 24 | 
            +
                parameters.each_with_object(resource) do |name, value, filtered_resource|
         | 
| 25 | 
            +
                  filter_method = filter_method_for(name)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  if !filter_method
         | 
| 28 | 
            +
                    filtered_resource
         | 
| 29 | 
            +
                  elsif filter_method.arity == 0
         | 
| 30 | 
            +
                    filtered_resource.public_send(filter_method.name)
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    filtered_resource.public_send(filter_method.name, value)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              private
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def filter_method_for(filter_item)
         | 
| 40 | 
            +
                filter_method_name = filter_method_name_for(filter_item)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                resource_class.method(filter_method_name) if filter_method_name
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def filter_method_name_for(filter_item)
         | 
| 46 | 
            +
                if resource_class.respond_to? "for_#{filter_item}"
         | 
| 47 | 
            +
                  "for_#{filter_item}"
         | 
| 48 | 
            +
                elsif resource_class.respond_to? filter_item
         | 
| 49 | 
            +
                  filter_item
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def resource_class
         | 
| 54 | 
            +
                @resource_class ||= if resource.respond_to? :klass
         | 
| 55 | 
            +
                                      resource.klass
         | 
| 56 | 
            +
                                    else
         | 
| 57 | 
            +
                                      resource
         | 
| 58 | 
            +
                                    end
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
            end
         | 
| 61 | 
            +
            end
         | 
| 62 | 
            +
            end
         | 
| 63 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require 'apill/parameters/index'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Apill
         | 
| 4 | 
            +
            module Resource
         | 
| 5 | 
            +
            module Processors
         | 
| 6 | 
            +
            class  Indexing
         | 
| 7 | 
            +
              attr_accessor :resource,
         | 
| 8 | 
            +
                            :parameters
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def initialize(resource, parameters)
         | 
| 11 | 
            +
                self.resource   = resource
         | 
| 12 | 
            +
                self.parameters = Parameters::Index.new(parameters['filter'] || {})
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def self.processed(*attrs)
         | 
| 16 | 
            +
                new(*attrs).processed
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def self.meta(*_attrs)
         | 
| 20 | 
            +
                {}
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def processed
         | 
| 24 | 
            +
                return resource unless resource.respond_to?(:for_query) &&
         | 
| 25 | 
            +
                                       parameters.query
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                resource.for_query(parameters.query)
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
            end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            require 'apill/parameters/page'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module  Apill
         | 
| 4 | 
            +
            module  Resource
         | 
| 5 | 
            +
            module  Processors
         | 
| 6 | 
            +
            class   Paging
         | 
| 7 | 
            +
              attr_accessor :resource,
         | 
| 8 | 
            +
                            :parameters
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def initialize(resource, parameters = {})
         | 
| 11 | 
            +
                self.resource   = resource
         | 
| 12 | 
            +
                self.parameters = Parameters::Page.new(parameters['page'] || {})
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def self.processed(*attrs)
         | 
| 16 | 
            +
                new(*attrs).processed
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def self.meta(*attrs)
         | 
| 20 | 
            +
                new(*attrs).meta
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def processed
         | 
| 24 | 
            +
                resource.page(parameters.page_number).
         | 
| 25 | 
            +
                         per(parameters.per_page)
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def meta
         | 
| 29 | 
            +
                {
         | 
| 30 | 
            +
                  'total-pages'   => processed.total_pages,
         | 
| 31 | 
            +
                  'current-page'  => processed.current_page,
         | 
| 32 | 
            +
                  'previous-page' => processed.prev_page,
         | 
| 33 | 
            +
                  'next-page'     => processed.next_page,
         | 
| 34 | 
            +
                }
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require 'apill/parameters/sort'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module  Apill
         | 
| 4 | 
            +
            module  Resource
         | 
| 5 | 
            +
            module  Processors
         | 
| 6 | 
            +
            class   Sorting
         | 
| 7 | 
            +
              attr_accessor :resource,
         | 
| 8 | 
            +
                            :parameters
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def initialize(resource, parameters = {})
         | 
| 11 | 
            +
                self.resource   = resource
         | 
| 12 | 
            +
                self.parameters = Parameters::Sort.new(parameters['sort'])
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def self.processed(*attrs)
         | 
| 16 | 
            +
                new(*attrs).processed
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def self.meta(*attrs)
         | 
| 20 | 
            +
                new(*attrs).meta
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def processed
         | 
| 24 | 
            +
                resource.order(parameters.to_h)
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def meta
         | 
| 28 | 
            +
                {
         | 
| 29 | 
            +
                  'sort' => parameters.to_h,
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
            end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            require 'apill/resource/model'
         | 
| 2 | 
            +
            require 'human_error/rescuable_resource'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module  Apill
         | 
| 5 | 
            +
            module  Resource
         | 
| 6 | 
            +
              module ClassMethods
         | 
| 7 | 
            +
                def plural_resource_name
         | 
| 8 | 
            +
                  name[/(\w+)Controller\z/, 1].
         | 
| 9 | 
            +
                  underscore.
         | 
| 10 | 
            +
                  pluralize.
         | 
| 11 | 
            +
                  downcase
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def singular_resource_name
         | 
| 15 | 
            +
                  name[/(\w+)Controller\z/, 1].
         | 
| 16 | 
            +
                  underscore.
         | 
| 17 | 
            +
                  singularize.
         | 
| 18 | 
            +
                  downcase
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def self.included(base)
         | 
| 23 | 
            +
                base.extend  ClassMethods
         | 
| 24 | 
            +
                base.include HumanError::RescuableResource
         | 
| 25 | 
            +
                base.include HumanError::VerifiableResource
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def api_resource
         | 
| 29 | 
            +
                @resource ||= Resource::Model.new(
         | 
| 30 | 
            +
                                resource:   public_send(self.class.plural_resource_name),
         | 
| 31 | 
            +
                                parameters: api_resource_params)
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def api_resource_params
         | 
| 35 | 
            +
                params.permit(sort:   String,
         | 
| 36 | 
            +
                              page:   %i{
         | 
| 37 | 
            +
                                number
         | 
| 38 | 
            +
                                size
         | 
| 39 | 
            +
                                offset
         | 
| 40 | 
            +
                                limit
         | 
| 41 | 
            +
                                cursor
         | 
| 42 | 
            +
                              },
         | 
| 43 | 
            +
                              filter: api_filterable_parameters)
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              def api_filterable_parameters
         | 
| 47 | 
            +
                @api_filterable_parameters ||= begin
         | 
| 48 | 
            +
                  filter_params     = params.fetch(:filter, {})
         | 
| 49 | 
            +
                  scalar_params     = [:query]
         | 
| 50 | 
            +
                  array_params      = {}
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  api_filterable_attributes.each do |api_filterable_attribute|
         | 
| 53 | 
            +
                    if filter_params[api_filterable_attribute].class == Array
         | 
| 54 | 
            +
                      array_params[api_filterable_attribute] = []
         | 
| 55 | 
            +
                    else
         | 
| 56 | 
            +
                      scalar_params << api_filterable_attribute
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  scalar_params << array_params
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              def api_filterable_attributes
         | 
| 65 | 
            +
                []
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         | 
| 68 | 
            +
            end
         | 
    
        data/lib/apill/version.rb
    CHANGED
    
    
    
        data/lib/apill.rb
    CHANGED
    
    | @@ -1,15 +1,10 @@ | |
| 1 | 
            -
            require 'kaminari'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            require 'apill/version'
         | 
| 4 2 |  | 
| 5 3 | 
             
            require 'apill/configuration'
         | 
| 6 4 | 
             
            require 'apill/matchers/accept_header_matcher'
         | 
| 7 5 | 
             
            require 'apill/matchers/subdomain_matcher'
         | 
| 8 6 | 
             
            require 'apill/matchers/version_matcher'
         | 
| 9 | 
            -
            require 'apill/ | 
| 10 | 
            -
            require 'apill/mixins/sortable'
         | 
| 11 | 
            -
            require 'apill/mixins/queryable'
         | 
| 12 | 
            -
            require 'apill/mixins/pageable'
         | 
| 7 | 
            +
            require 'apill/resource'
         | 
| 13 8 | 
             
            require 'apill/serializers/json_api'
         | 
| 14 9 |  | 
| 15 10 | 
             
            require 'apill/middleware/api_request'
         | 
| @@ -10,29 +10,20 @@ describe  InvalidApiRequestError do | |
| 10 10 | 
             
                expect(error.http_status).to eql 400
         | 
| 11 11 | 
             
              end
         | 
| 12 12 |  | 
| 13 | 
            -
              it 'has a code | 
| 14 | 
            -
                expect(error.code).to eql  | 
| 13 | 
            +
              it 'has a code' do
         | 
| 14 | 
            +
                expect(error.code).to eql 'errors.invalid_api_request_error'
         | 
| 15 15 | 
             
              end
         | 
| 16 16 |  | 
| 17 | 
            -
              it ' | 
| 18 | 
            -
                expect(error. | 
| 17 | 
            +
              it 'can output the detail' do
         | 
| 18 | 
            +
                expect(error.detail).to eql 'The accept header that you passed in the ' \
         | 
| 19 | 
            +
                                            'request cannot be parsed, please refer to ' \
         | 
| 20 | 
            +
                                            'the documentation to verify.'
         | 
| 19 21 | 
             
              end
         | 
| 20 22 |  | 
| 21 | 
            -
              it 'can output the  | 
| 22 | 
            -
                expect(error.developer_message).to eql 'The accept header that you passed in the ' \
         | 
| 23 | 
            -
                                                       'request cannot be parsed, please refer to ' \
         | 
| 24 | 
            -
                                                       'the documentation to verify.'
         | 
| 25 | 
            -
              end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
              it 'can output the developer details' do
         | 
| 23 | 
            +
              it 'can output the source' do
         | 
| 28 24 | 
             
                error = InvalidApiRequestError.new accept_header: 'foo'
         | 
| 29 25 |  | 
| 30 | 
            -
                expect(error. | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              it 'can output the friendly message' do
         | 
| 34 | 
            -
                expect(error.friendly_message).to eql "Sorry! We couldn't understand what you were " \
         | 
| 35 | 
            -
                                                      'trying to ask us to do.'
         | 
| 26 | 
            +
                expect(error.source).to eql(accept_header: 'foo')
         | 
| 36 27 | 
             
              end
         | 
| 37 28 | 
             
            end
         | 
| 38 29 | 
             
            end
         | 
| @@ -10,29 +10,20 @@ describe  InvalidSubdomainError do | |
| 10 10 | 
             
                expect(error.http_status).to eql 404
         | 
| 11 11 | 
             
              end
         | 
| 12 12 |  | 
| 13 | 
            -
              it 'has a code | 
| 14 | 
            -
                expect(error.code).to eql  | 
| 13 | 
            +
              it 'has a code' do
         | 
| 14 | 
            +
                expect(error.code).to eql 'errors.invalid_subdomain_error'
         | 
| 15 15 | 
             
              end
         | 
| 16 16 |  | 
| 17 | 
            -
              it ' | 
| 18 | 
            -
                expect(error. | 
| 19 | 
            -
              end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              it 'can output the developer message' do
         | 
| 22 | 
            -
                expect(error.developer_message).to eql \
         | 
| 17 | 
            +
              it 'can output the detail' do
         | 
| 18 | 
            +
                expect(error.detail).to eql \
         | 
| 23 19 | 
             
                  'The resource you attempted to access is either not authorized for the ' \
         | 
| 24 20 | 
             
                  'authenticated user or does not exist.'
         | 
| 25 21 | 
             
              end
         | 
| 26 22 |  | 
| 27 | 
            -
              it 'can output the  | 
| 23 | 
            +
              it 'can output the source' do
         | 
| 28 24 | 
             
                error = InvalidSubdomainError.new http_host: 'foo'
         | 
| 29 25 |  | 
| 30 | 
            -
                expect(error. | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              it 'can output the friendly message' do
         | 
| 34 | 
            -
                expect(error.friendly_message).to eql \
         | 
| 35 | 
            -
                  'Sorry! The resource you tried to access does not exist.'
         | 
| 26 | 
            +
                expect(error.source).to eql(http_host: 'foo')
         | 
| 36 27 | 
             
              end
         | 
| 37 28 | 
             
            end
         | 
| 38 29 | 
             
            end
         | 
| @@ -3,43 +3,39 @@ require 'apill/responses/invalid_subdomain_response' | |
| 3 3 |  | 
| 4 4 | 
             
            module    Apill
         | 
| 5 5 | 
             
            module    Responses
         | 
| 6 | 
            -
            describe  InvalidSubdomainResponse do
         | 
| 7 | 
            -
              before(:each) do
         | 
| 8 | 
            -
                HumanError.configuration.api_error_documentation_url = 'http://error.com'
         | 
| 9 | 
            -
                HumanError.configuration.knowledgebase_url           = 'http://knowledge.com'
         | 
| 10 | 
            -
                HumanError.configuration.api_version                 = '1'
         | 
| 11 | 
            -
              end
         | 
| 12 | 
            -
             | 
| 6 | 
            +
            describe  InvalidSubdomainResponse, singletons: HumanError::Configuration do
         | 
| 13 7 | 
             
              it 'returns the proper response' do
         | 
| 14 | 
            -
                 | 
| 15 | 
            -
             | 
| 8 | 
            +
                HumanError.configuration.url_mappings = {
         | 
| 9 | 
            +
                  'external_documentation_urls'  => {
         | 
| 10 | 
            +
                    'errors.invalid_subdomain_response' => 'http://example.com/foo',
         | 
| 11 | 
            +
                  },
         | 
| 12 | 
            +
                  'developer_documentation_urls' => {
         | 
| 13 | 
            +
                    'errors.invalid_subdomain_response' => 'http://example.com/foo',
         | 
| 14 | 
            +
                  },
         | 
| 15 | 
            +
                }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                request                   = { 'HTTP_HOST' => 'api.example.com' }
         | 
| 18 | 
            +
                status, headers, response = InvalidSubdomainResponse.call(request)
         | 
| 16 19 |  | 
| 17 | 
            -
                expect( | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                     | 
| 22 | 
            -
                      ' | 
| 23 | 
            -
             | 
| 24 | 
            -
                        ' | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
                            '},' \
         | 
| 37 | 
            -
                          '"friendly_message_key":"errors.invalid.subdomain.error.friendly",' \
         | 
| 38 | 
            -
                          '"friendly_message":"Sorry! The resource you tried to access does not ' \
         | 
| 39 | 
            -
                                              'exist."' \
         | 
| 40 | 
            -
                        '}' \
         | 
| 41 | 
            -
                      '}',
         | 
| 42 | 
            -
                    ],
         | 
| 20 | 
            +
                expect(status).to                 eql 404
         | 
| 21 | 
            +
                expect(headers).to                eql({})
         | 
| 22 | 
            +
                expect(JSON.load(response[0])).to include(
         | 
| 23 | 
            +
                  'errors'              => [
         | 
| 24 | 
            +
                    include(
         | 
| 25 | 
            +
                      'id'     => match(/[a-f0-9\-]+/),
         | 
| 26 | 
            +
                      'links'  => {
         | 
| 27 | 
            +
                        'about'         => nil,
         | 
| 28 | 
            +
                        'documentation' => nil,
         | 
| 29 | 
            +
                      },
         | 
| 30 | 
            +
                      'status' => 404,
         | 
| 31 | 
            +
                      'code'   => 'errors.invalid_subdomain_error',
         | 
| 32 | 
            +
                      'title'  => 'Invalid Subdomain',
         | 
| 33 | 
            +
                      'detail' => 'The resource you attempted to access is either not authorized ' \
         | 
| 34 | 
            +
                                  'for the authenticated user or does not exist.',
         | 
| 35 | 
            +
                      'source' => {
         | 
| 36 | 
            +
                        'http_host'     => 'api.example.com',
         | 
| 37 | 
            +
                      },
         | 
| 38 | 
            +
                    ),
         | 
| 43 39 | 
             
                  ],
         | 
| 44 40 | 
             
                )
         | 
| 45 41 | 
             
              end
         |