0

I've tried to follow some questions with no luck:

Due to outside of context issue I created a limiter function in a util.py file as follow:

def limiter():
    _limiter = Limiter(
        app,
        key_func=get_remote_address
    )
    return _limiter

And in my Flask-Restful API resource I have called this limiter in method-decorators:

from ..utils import limiter

class UsersView(Resource, CustomAPIMixin):
     method_decorators = [limiter().limit("1/minute", methods=["GET"])]

     @jwt_authenticate()
     def get(self):
         user_id = get_jwt_identity()
         return self.api_response(content={"user_id": user_id})

NOTE: I'm using Flask version 2 and Flask-Limiter 1.4


EDIT-1:

my_api
    models
    scripts
    views
         users.py
    __init__.py  # contains create_app() to return Flask app
    utils.py. # contains custom rate_limit() function

EDIT-2: Here is the full working code that Flask-Limiter does not work on:

Alireza
  • 6,497
  • 13
  • 59
  • 132

1 Answers1

1

The Flask-Limiter documentation gives an example that fits this case: https://flask-limiter.readthedocs.io/en/stable/#using-flask-pluggable-views

If you set decorators instead of method_decorators it should fix your issue.

Here is a fully working sample that demonstrates rate limiting for the provided code.

from flask import Flask
from flask_restful import Resource, Api
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address


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


def limiter():
    _limiter = Limiter(
        app,
        key_func=get_remote_address
    )
    return _limiter


class CustomAPIMixin:
    def api_response(self, content):
        return content


def get_jwt_identity():
    return 0


class UsersView(Resource, CustomAPIMixin):
    decorators = [limiter().limit("1/minute", methods=["GET"])]

    # @jwt_authenticate()
    def get(self):
        user_id = get_jwt_identity()
        return self.api_response(content={"user_id": user_id})


api.add_resource(UsersView, '/')

if __name__ == '__main__':
    app.run(debug=True)
GitFront
  • 894
  • 3
  • 11
  • This is weird that your code works in a separate file, but when I put in my own code structure I get no errors for rate limit! – Alireza Aug 08 '21 at 06:35
  • Please check *Edit-1* for more info. – Alireza Aug 08 '21 at 07:10
  • I would need a minimal example that doesn't work correctly to find out why it's not working. Otherwise I can't be sure I found the same problem that you have. – GitFront Aug 08 '21 at 11:02
  • Please kindly check this repo that ratelimit does not work on: https://github.com/alirezastack/ratelimit_api – Alireza Aug 09 '21 at 08:50
  • In your code you are initializing the limiter with an uninitialized current_app. You need to pass the app to the limiter. Hope this helps. Otherwise, create another question and include all relevant information so that it can be useful to other SO users. – GitFront Aug 09 '21 at 16:49
  • You mean in __init__ of View class? Because otherwise I have imported current_app in `utils.py` and used current_app in `Flask-Limiter`. Thank you very much for your help. – Alireza Aug 10 '21 at 06:45
  • From the [docs](https://flask.palletsprojects.com/en/2.0.x/appcontext/#purpose-of-the-context), `current_app` should not be available from `utils.py` unless you import it in a context. For a quick solution set `ProfileView.decorators` in `app_routes` function where you have the `app` available. – GitFront Aug 10 '21 at 17:03
  • +1 That solved the isuue! Thanks. :) so it was a false understanding that in utils.py I have access to my current ongoing app context. – Alireza Aug 11 '21 at 09:38