ruby-on-railsrubyjsonapi-resources

how to specify maximum_page_size config per resoruce in JR gem


So I have a rails application that use jsonapi-resources gem and in global config specified this config

JSONAPI.configure do |config|
  config.maximum_page_size = 1000
end

https://jsonapi-resources.com/v0.10/guide/basic_usage.html

But I want to use custom maximum_page_size in separate API resources for example /api/logs

module Api
  class LogResource < ApplicationResource
    immutable
    model_name 'Api::Log'
    primary_key :uuid

    def self.default_sort
      [{ field: 'time_start', direction: :desc }]
    end
  end
end

SO My question how to specify config only for this specific JSON API resource?


Solution

  • From what I can determine in the source code maximum_page_size cannot be directly overridden at a resource level, so it appears the best way to handle this would be to implement a custom Paginator.

    For your given example I think something as simple as the following should work:

    class LimitedPageSizePaginator < PagedPaginator 
      MAX_PAGE_SIZE = 100 
      def initialize(params) 
        super
        verify_page_size_limit
      end 
    
      private 
        def verify_page_size_limit
          if @size > MAX_PAGE_SIZE
            fail JSONAPI::Exceptions::InvalidPageValue.new(:size, @size,
                    detail: "size exceeds maximum page size of #{MAX_PAGE_SIZE}.")
          end
        end 
    end 
    

    Then you should be able to specify the Paginator for your resource

    module Api
      class LogResource < ApplicationResource
        immutable
        model_name 'Api::Log'
        primary_key :uuid
       
        paginator :limited_page_size
        
        def self.default_sort
          [{ field: 'time_start', direction: :desc }]
        end
      end
    end
    

    If you need to make this more flexible e.g. not a fixed constant. Then we would need to create a method that dynamically creates a class on on the fly with the appropriate limitation set and then utilize that as the Paginator, something like.

    module PaginatorCreator 
      class LimitedPaginator < PagedPaginator 
        class << self 
          attr_accessor :limit
          def paginator_name
            self.name.demodulize.underscore[..-11].to_sym
          end 
        end 
    
        def initialize(params) 
          super
          verify_page_size_limit
        end 
    
        private 
          def verify_page_size_limit
            if @size > self.class.limit
              fail JSONAPI::Exceptions::InvalidPageValue.new(:size, @size,
                      detail: "size exceeds maximum page size of #{self.class.limit}.")
            end
          end 
      end
    
      def self.create_limited_paginator(resource:,limit:) 
        klass = Object.const_set("#{resource.name.demodulize}LimitedPaginator",Class.new(LimitedPaginator)) 
        klass.limit = limit
        resource.paginator(klass.paginator_name)
      end 
    end 
    

    Then use as

    class LogResource < ApplicationResource
        PaginatorCreator.create_limited_paginator(resource: self, limit: 100)
    end  
    

    Please Note: I have not used this library so there may be better solutions.