diff --git a/README.md b/README.md index e4f5f74..2cfeaf6 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,15 @@ class MoviesAPI < Grape::API get :cast do paginate Movie.find(params[:id]).actors end + + desc "Return one movie's awards, paginated" + # Enforce max_per_page value will add the alowed values + # to the swagger docs, and cause grape to return an error + # if outside that range + paginate per_page: 10, max_per_page: 200, enforce_max_per_page: true + get :awards do + paginate Movie.find(params[:id]).awards + end end end ``` diff --git a/lib/grape/pagination.rb b/lib/grape/pagination.rb index b6791ee..6c1e4c5 100644 --- a/lib/grape/pagination.rb +++ b/lib/grape/pagination.rb @@ -39,11 +39,16 @@ def paginate(collection) def self.paginate(options = {}) route_setting :per_page, options[:per_page] route_setting :max_per_page, options[:max_per_page] + + enforce_max_per_page = options[:max_per_page] && options[:enforce_max_per_page] + per_page_values = enforce_max_per_page ? 0..options[:max_per_page] : nil + params do - optional :page, :type => Integer, :default => 1, - :desc => 'Page of results to fetch.' - optional :per_page, :type => Integer, - :desc => 'Number of results to return per page.' + optional :page, :type => Integer, :default => 1, + :desc => 'Page of results to fetch.' + optional :per_page, :type => Integer, + :desc => 'Number of results to return per page.', + :values => per_page_values end end end diff --git a/spec/grape_spec.rb b/spec/grape_spec.rb index 4a0b86d..8de7df6 100644 --- a/spec/grape_spec.rb +++ b/spec/grape_spec.rb @@ -56,15 +56,35 @@ it_behaves_like 'an endpoint with a middle page' end - context 'with a max_per_page setting' do + context 'without a max_per_page setting' do before { get '/numbers', :count => 100, :per_page => 30 } + it 'should list all numbers within per page in the response body' do + body = '[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]' + + expect(last_response.body).to eq(body) + end + end + + context 'with a max_per_page setting not enforced' do + before { get '/numbers_with_max_per_page', :count => 100, :per_page => 30 } + it 'should not go above the max_per_page_limit' do body = '[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]' expect(last_response.body).to eq(body) end end + + context 'with a max_per_page setting enforced' do + before { get '/numbers_with_enforced_max_per_page', :count => 100, :per_page => 30 } + + it 'should not allow value above the max_per_page_limit' do + body = '{"error":"per_page does not have a valid value"}' + + expect(last_response.body).to eq(body) + end + end end context 'with custom response headers' do diff --git a/spec/support/numbers_api.rb b/spec/support/numbers_api.rb index ae0f89d..7c29d8e 100644 --- a/spec/support/numbers_api.rb +++ b/spec/support/numbers_api.rb @@ -5,7 +5,7 @@ class NumbersAPI < Grape::API format :json desc 'Return some paginated set of numbers' - paginate :per_page => 10, :max_per_page => 25 + paginate :per_page => 10 params do requires :count, :type => Integer optional :with_headers, :default => false, :type => Boolean @@ -20,4 +20,22 @@ class NumbersAPI < Grape::API paginate (1..params[:count]).to_a end + + desc 'Return some paginated set of numbers with max_per_page' + paginate :per_page => 10, :max_per_page => 25 + params do + requires :count, :type => Integer + end + get :numbers_with_max_per_page do + paginate (1..params[:count]).to_a + end + + desc 'Return some paginated set of numbers with max_per_page enforced' + paginate :per_page => 10, :max_per_page => 25, :enforce_max_per_page => true + params do + requires :count, :type => Integer + end + get :numbers_with_enforced_max_per_page do + paginate (1..params[:count]).to_a + end end