Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask restful pagination

I need to throw together an very simple API with a short deadline. Flask-restful seems ideal except for one thing: I can't find anything in the documentation about pagination. Given a simple endpoint like this:

from flask import Flask, request 
from flask_restful import Resource, Api 
from sqlalchemy import create_engine
import json 

app = Flask(__name__)
api = Api(app)

class Employees(Resource):
    def get(self):
        return json.dumps([{'employees': 'hello world'} for i in range(1000)])

api.add_resource(Employees, '/employees')

if __name__ == '__main__':
    app.run(port='5002')

Is there any way for flask_restful to paginate the endpoint so that I only receive, say, 100 of those dictionaries per page, and have URLs for 'next' and 'previous'? If not, is it maybe possible to create pagination some other way in Flask? Thanks.

like image 510
Neil Avatar asked Apr 05 '19 20:04

Neil


People also ask

How do you handle pagination in flask?

Modify the view to cater to pagination. Results are paginated using the paginate function of Flask SQLAlchemy with any number of arguments as desired. The result of calling the paginate() function is a Pagination Object, which has many methods that can help you achieve your desired result.

Is flask GOOD FOR REST API?

Being lightweight, easy to adopt, well-documented, and popular, Flask is a good option for developing RESTful APIs.


1 Answers

You can either use:

  • Pagination provided by flask_sqlalchemy (API documentation can be found here)
  • Custom method to paginate existing data as shown in this tutorial by Avi Aryan.

As I am not sure if you are using flask_sqlalchemy or any model information, I am showing the custom pagination technique.

I have modified the data to show the employee id. And I also used jsonify from Flask.

from flask import Flask, request, jsonify, abort
from flask_restful import Resource, Api 


app = Flask(__name__)
api = Api(app)

data = [{'employee_id': i+1} for i in range(1000)]

def get_paginated_list(results, url, start, limit):
    start = int(start)
    limit = int(limit)
    count = len(results)
    if count < start or limit < 0:
        abort(404)
    # make response
    obj = {}
    obj['start'] = start
    obj['limit'] = limit
    obj['count'] = count
    # make URLs
    # make previous url
    if start == 1:
        obj['previous'] = ''
    else:
        start_copy = max(1, start - limit)
        limit_copy = start - 1
        obj['previous'] = url + '?start=%d&limit=%d' % (start_copy, limit_copy)
    # make next url
    if start + limit > count:
        obj['next'] = ''
    else:
        start_copy = start + limit
        obj['next'] = url + '?start=%d&limit=%d' % (start_copy, limit)
    # finally extract result according to bounds
    obj['results'] = results[(start - 1):(start - 1 + limit)]
    return obj

class Employees(Resource):
    def get(self):
        return jsonify(get_paginated_list(
        data, 
        '/employees', 
        start=request.args.get('start', 1), 
        limit=request.args.get('limit', 20)
    ))

api.add_resource(Employees, '/employees')

if __name__ == '__main__':
    app.run(port='5002', debug=True)

Output:

paginated output

Footnote:

  • API can be called with parameter or without parameter. Example of valid API calls:
    • http://127.0.0.1:5002/employees
    • http://127.0.0.1:5002/employees?start=41&limit=20
    • http://127.0.0.1:5002/employees?limit=5
    • http://127.0.0.1:5002/employees?start=100
  • Default value for start is 1 and limit is 20.
  • If the start value is greater than data length or limit is negative then the API will return HTTP 404 error with an error message:

HTTP 404 error

like image 127
arsho Avatar answered Sep 20 '22 06:09

arsho