Skip to content

Commit

Permalink
Return 200 rather than 404 if pagination out of range
Browse files Browse the repository at this point in the history
  • Loading branch information
lafrech committed Sep 26, 2018
1 parent 24a2eeb commit 33722f6
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 27 deletions.
4 changes: 0 additions & 4 deletions flask_rest_api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ class InvalidLocation(FlaskRestApiError):
"""Parameter location is not a valid location"""


class PageOutOfRangeError(FlaskRestApiError):
"""Requested page number out of page range"""


class NotModified(wexc.HTTPException, FlaskRestApiError):
"""Resource was not modified (Etag is unchanged)
Expand Down
29 changes: 10 additions & 19 deletions flask_rest_api/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@

import marshmallow as ma

from .args_parser import abort, parser
from .args_parser import parser
from .utils import get_appcontext
from .exceptions import PageOutOfRangeError
from .compat import MARSHMALLOW_VERSION_MAJOR


Expand Down Expand Up @@ -86,7 +85,6 @@ def make_paginator(self, data):
class PaginationMetadata:

def __init__(self, page, page_size, item_count):
self.page = page
self.page_size = page_size
self.item_count = item_count

Expand All @@ -97,17 +95,13 @@ def __init__(self, page, page_size, item_count):
self.first_page = 1
self.page_count = ((self.item_count - 1) // self.page_size) + 1
self.last_page = self.first_page + self.page_count - 1
# Check if requested page number is out of range
if (self.page < self.first_page) or (self.page > self.last_page):
raise PageOutOfRangeError(
"Page {} out of [{}-{}] range.".format(
self.page, self.first_page, self.last_page)
)
# Previous / next page
if self.page > self.first_page:
self.previous_page = self.page-1
if self.page < self.last_page:
self.next_page = self.page+1
# Page, previous / next page
if page <= self.last_page:
self.page = page
if page > self.first_page:
self.previous_page = page - 1
if page < self.last_page:
self.next_page = page + 1

def __repr__(self):
return ("{}(page={!r},page_size={!r},item_count={!r})"
Expand Down Expand Up @@ -188,11 +182,8 @@ def _set_pagination_header(page_params):
current_app.logger.warning(
'item_count not set in endpoint {}'.format(request.endpoint))
return
try:
pagination_metadata = PaginationMetadata(
page_params.page, page_params.page_size, item_count)
except PageOutOfRangeError as exc:
abort(404, messages=str(exc), exc=exc)
pagination_metadata = PaginationMetadata(
page_params.page, page_params.page_size, item_count)
page_header = PaginationMetadataSchema().dumps(pagination_metadata)
if MARSHMALLOW_VERSION_MAJOR < 3:
page_header = page_header[0]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def assert_counters(
list_etag = response.headers['ETag']
assert len(response.json) == 0
assert json.loads(response.headers['X-Pagination']) == {
'total': 0, 'total_pages': 0, 'page': 1}
'total': 0, 'total_pages': 0}

# GET collection with correct ETag: Not modified
with assert_counters(0, 1, 0, 1 if bp_schema == 'ETag schema' else 0):
Expand Down
20 changes: 17 additions & 3 deletions tests/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,27 @@ def test_pagination_parameters_default_page_page_size(self, app_fixture):
'previous_page': 1, 'next_page': 3,
}

def test_pagination_empty_collection(self, app_fixture):
# empty collection -> 200 with empty list, partial pagination metadata
response = app_fixture.client.get('/test/')
assert response.status_code == 200
assert json.loads(response.headers['X-Pagination']) == {
'total': 0, 'total_pages': 0,
}
assert response.json == []

@pytest.mark.parametrize('collection', [1000, ], indirect=True)
def test_pagination_page_out_of_range(self, app_fixture):
# page = 120, page_size = 10: page out of range -> 404
# page = 120, page_size = 10
# page out of range -> 200 with empty list, partial pagination metadata
response = app_fixture.client.get(
'/test/', query_string={'page': 120, 'page_size': 10})
assert response.status_code == 404
assert 'errors' in response.json
assert response.status_code == 200
assert json.loads(response.headers['X-Pagination']) == {
'total': 1000, 'total_pages': 100,
'first_page': 1, 'last_page': 100,
}
assert response.json == []

@pytest.mark.parametrize('collection', [1000, ], indirect=True)
def test_pagination_min_page_page_size(self, app_fixture):
Expand Down

0 comments on commit 33722f6

Please sign in to comment.