Add default limit and max limit config vars

This commit is contained in:
Nathan Barber
2021-04-16 13:11:57 -04:00
parent 100111ed2c
commit 3c328385a4
6 changed files with 58 additions and 22 deletions

View File

@@ -108,7 +108,7 @@ paths:
description: | description: |
Return a finite number of users. Return a finite number of users.
Can be used with offset to paginate. Can be used with offset to paginate.
If unspecified, return all users. If unspecified, use api_page_default_limit.
responses: responses:
"200": "200":
description: The Hub's user list description: The Hub's user list
@@ -455,7 +455,7 @@ paths:
description: | description: |
Return a finite number of groups. Return a finite number of groups.
Can be used with offset to paginate. Can be used with offset to paginate.
If unspecified, return all groups. If unspecified, use api_page_default_limit.
responses: responses:
"200": "200":
description: The list of groups description: The list of groups
@@ -487,7 +487,7 @@ paths:
description: | description: |
Return a finite number of users within the given group. Return a finite number of users within the given group.
Can be used with offset to paginate. Can be used with offset to paginate.
If unspecified, return all users. If unspecified, use api_page_default_limit
responses: responses:
"200": "200":
description: The group model description: The group model
@@ -610,7 +610,7 @@ paths:
description: | description: |
Return a finite number of routes. Return a finite number of routes.
Can be used with offset to paginate. Can be used with offset to paginate.
If unspecified, return all routes. If unspecified, use api_page_default_limit
responses: responses:
"200": "200":
description: Routing table description: Routing table

View File

@@ -175,6 +175,8 @@ r.raise_for_status()
r.json() r.json()
``` ```
By default, pagination limit will be specified by the `JupyterHub.api_page_default_limit` config variable.
Pagination is enabled on the `GET /users`, `GET /groups`, `GET /groups/{name}`, and `GET /proxy` REST endpoints. Pagination is enabled on the `GET /users`, `GET /groups`, `GET /groups/{name}`, and `GET /proxy` REST endpoints.
## Enabling users to spawn multiple named-servers via the API ## Enabling users to spawn multiple named-servers via the API

View File

@@ -39,7 +39,8 @@ class GroupListAPIHandler(_GroupAPIHandler):
def get(self): def get(self):
"""List groups""" """List groups"""
offset = self.get_argument("offset", None) offset = self.get_argument("offset", None)
limit = self.get_argument("limit", None) limit = self.get_argument("limit", self.settings['app'].api_page_default_limit)
max_limit = self.settings['app'].api_page_max_limit
query = self.db.query(orm.Group) query = self.db.query(orm.Group)
@@ -52,14 +53,18 @@ class GroupListAPIHandler(_GroupAPIHandler):
) )
query = query.offset(offset) query = query.offset(offset)
if limit is not None: if limit != self.settings['app'].api_page_default_limit:
try: try:
limit = int(limit) limit = int(limit)
if limit > max_limit:
limit = max_limit
except Exception as e: except Exception as e:
raise web.HTTPError( raise web.HTTPError(
400, "Invalid argument type, limit must be an integer" 400, "Invalid argument type, limit must be an integer"
) )
query = query.limit(int(limit))
query = query.limit(limit)
data = [self.group_model(group) for group in query] data = [self.group_model(group) for group in query]
self.write(json.dumps(data)) self.write(json.dumps(data))
@@ -100,13 +105,12 @@ class GroupAPIHandler(_GroupAPIHandler):
@admin_only @admin_only
def get(self, name): def get(self, name):
offset = self.get_argument("offset", None) offset = self.get_argument("offset", None)
limit = self.get_argument("limit", None) limit = self.get_argument("limit", self.settings['app'].api_page_default_limit)
max_limit = self.settings['app'].api_page_max_limit
group = self.find_group(name) group = self.find_group(name)
users_slice = None users_slice = None
print(type(group.users))
print(group.users)
if offset is not None: if offset is not None:
try: try:
offset = int(offset) offset = int(offset)
@@ -117,9 +121,11 @@ class GroupAPIHandler(_GroupAPIHandler):
group.users = group.users[offset:] group.users = group.users[offset:]
if limit is not None: if limit != self.settings['app'].api_page_default_limit:
try: try:
limit = int(limit) limit = int(limit)
if limit > max_limit:
limit = max_limit
except Exception as e: except Exception as e:
raise web.HTTPError( raise web.HTTPError(
400, "Invalid argument type, limit must be an integer" 400, "Invalid argument type, limit must be an integer"

View File

@@ -18,7 +18,8 @@ class ProxyAPIHandler(APIHandler):
but without clients needing to maintain separate but without clients needing to maintain separate
""" """
offset = self.get_argument("offset", None) offset = self.get_argument("offset", None)
limit = self.get_argument("limit", None) limit = self.get_argument("limit", self.settings['app'].api_page_default_limit)
max_limit = self.settings['app'].api_page_max_limit
routes = await self.proxy.get_all_routes() routes = await self.proxy.get_all_routes()
@@ -35,9 +36,11 @@ class ProxyAPIHandler(APIHandler):
if key in routes if key in routes
} }
if limit is not None: if limit != self.settings['app'].api_page_default_limit:
try: try:
limit = int(limit) limit = int(limit)
if limit > max_limit:
limit = max_limit
except Exception as e: except Exception as e:
raise web.HTTPError( raise web.HTTPError(
400, "Invalid argument type, limit must be an integer" 400, "Invalid argument type, limit must be an integer"

View File

@@ -56,7 +56,8 @@ class UserListAPIHandler(APIHandler):
def get(self): def get(self):
state_filter = self.get_argument("state", None) state_filter = self.get_argument("state", None)
offset = self.get_argument("offset", None) offset = self.get_argument("offset", None)
limit = self.get_argument("limit", None) limit = self.get_argument("limit", self.settings['app'].api_page_default_limit)
max_limit = self.settings['app'].api_page_max_limit
# post_filter # post_filter
post_filter = None post_filter = None
@@ -99,10 +100,25 @@ class UserListAPIHandler(APIHandler):
# Apply offset and limit for request pagination # Apply offset and limit for request pagination
if offset is not None: if offset is not None:
query = query.offset(int(offset)) try:
offset = int(offset)
except Exception as e:
raise web.HTTPError(
400, "Invalid argument type, offset must be an integer"
)
query = query.offset(offset)
if limit is not None: if limit != self.settings['app'].api_page_default_limit:
query = query.limit(int(limit)) try:
limit = int(limit)
if limit > max_limit:
limit = max_limit
except Exception as e:
raise web.HTTPError(
400, "Invalid argument type, limit must be an integer"
)
query = query.limit(limit)
data = [ data = [
self.user_model(u, include_servers=True, include_state=True) self.user_model(u, include_servers=True, include_state=True)

View File

@@ -936,6 +936,15 @@ class JupyterHub(Application):
""", """,
).tag(config=True) ).tag(config=True)
api_page_default_limit = Integer(
50,
help="The default amount of records returned by a paginated endpoint",
).tag(config=True)
api_page_max_limit = Integer(
200, help="The maximum amount of records that can be returned at once"
)
authenticate_prometheus = Bool( authenticate_prometheus = Bool(
True, help="Authentication for prometheus metrics" True, help="Authentication for prometheus metrics"
).tag(config=True) ).tag(config=True)