2

I believe I have the same problem as described here: Flask-Limiter does not work with Flask-Restful API-based application. But I still can't get it to work. Here's my problem:

This is the rate-limiter file (located in: /controller/helpers/rate_limiter.py)

from flask import current_app
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    current_app,
    key_func=get_remote_address
)

This is the app.py file (located in: /):

from flask import Flask
from flask_restful import Api
from controller.actions.my_endpoint import MyEndpoint

flask_app = Flask(__name__)
api = Api(flask_app)
api.add_resource(MyEndpoint, '/endpoint')
flask_app.run(debug=True, use_reloader=True, host='0.0.0.0', port=8000)

And finally this is an example of an endpoint (located in: /controller/actions/my_endpoint):

from flask_restful import reqparse, Resource
from controller.helpers.rate_limiter import limiter


class MyEndpoint(Resource):
    decorators = [limiter.limit("1/minute", methods=["POST"])]
    
    def __init__(self):
        self.parser = reqparse.RequestParser()
        self.parser.add_argument(
            "someData", type=int, nullable=False, required=True)

    def post(self):
        data = self.parser.parse_args(strict=True)
        someData = data.someData

        return "Got your message {0}".format(someData), 200

I would expect that after the first request I would get response 429 because the rate limit of 1/minute is reached but it doesn't do that.

However, when I instantiate the limiter inside app.py and set a default rate-limit, it works (getting that error 429):

from flask import Flask
from flask_restful import Api
from controller.db_actions.my_endpoint import MyEndpoint
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

flask_app = Flask(__name__)

limiter = Limiter(
    flask_app,
    key_func=get_remote_address,
    default_limits=["1 per minute"]
)

api = Api(flask_app)
api.add_resource(MyEndpoint, '/endpoint')
flask_app.run(debug=True, use_reloader=True, host='0.0.0.0', port=8000)

Question: I think I'm doing something wrong with instantiating the limiter. What is it? :)

  • Interesting... I'm seeing the same issue here. I guess you never figured it out? I have it working if I instantiate it in __init__.py where I declare my app but if I try to instantiate it with current_app in a blueprint file it doesn't seem to work. Curious. – Kenny Pyatt Aug 14 '23 at 19:41

1 Answers1

0

I got around this by using a utils.py file and importing limiter from that.

In utils.py

from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

# Setup the Rate Limiter
limiter = Limiter(
    get_remote_address,
    default_limits=["100 per hour", "10 per minute"],
    storage_uri="memory://",
)

Then I imported it and used the init_app() method on the limiter to make it work as expected.

In the __init__.py

from .utils import limiter

app = Flask(__name__, static_folder="static", static_url_path="/static")

limiter.init_app(app)

Now I can import it into my blueprint and it works:

from rest_api.utils import limiter

@employee_blueprint.route("/")
@limiter.limit("1 per second")
def get_employees(session=""):
   ... code here ...

I was inspired by this article.

Kenny Pyatt
  • 363
  • 1
  • 4
  • 17