gogasca
gogasca

Reputation: 10058

Python Rate Limit class based view Flask

I'm following this example:

http://flask-limiter.readthedocs.org/en/stable/#ratelimit-string

app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address)

class MyView(flask.views.MethodView):
    decorators = [limiter.limit("10/second")]
    def get(self):
        return "get"

    def put(self):
        return "put"

My problem is that in example, the application, limiter and classes are defined in the same file in my case the application and limiter are defined in the same file but my classes live in a separate file.

If I import either limiter or app my Flask app doesn't start because circular dependencies. How can fix this, what is the recommended way? I want to apply limiter to specific endpoints. I tried from flask import current_appin order to initialize limiter but this function was not take it as a valid parameter. Any recommendations?

File information:

Under app.py I have defined my resources:

api_app = Flask(__name__)  # Flask Application
api_app.config.from_pyfile("../../../conf/settings.py")  # Flask configuration

imbue_api = restful.Api(api_app)  # Define API
limiter = Limiter(api_app, key_func=get_remote_address, global_limits=["10 per second"])

imbue_api.add_resource(ApiBase, settings.BASE_API_URL)

In api_main.py I have defined all my classes:

class ApiBase(Resource):
    @authenticator.requires_auth
    def get(self):
        """

        :return:
        """
        try:
            # =========================================================
            # GET API
            # =========================================================
            log.info(request.remote_addr + ' ' + request.__repr__())
            if request.headers['Content-Type'] == 'application/json':
                # =========================================================
                # Send API version information
                # =========================================================
                log.info('api() | GET | Version' + settings.api_version)
                response = json.dumps('version: ' + settings.api_version)
                resp = Response(response, status=200, mimetype='application/json')
                return resp

        except KeyError:
            response = json.dumps('Invalid type headers. Use application/json')
            resp = Response(response, status=415, mimetype='application/json')
            return resp

        except Exception, exception:
            log.exception(exception.__repr__())
            response = json.dumps('Internal Server Error')
            resp = Response(response, status=500, mimetype='application/json')
            return resp

Upvotes: 3

Views: 1772

Answers (1)

iurisilvio
iurisilvio

Reputation: 4987

Use the Resource.method_decorators

https://github.com/flask-restful/flask-restful/blob/master/flask_restful/init.py#L574

It is applied for each request. You can override it in your view class:

@property
def method_decorators(self):
    # get some limiter bound to the `g` context
    # maybe you prefer to get it from `current_app`
    return g.limiter

If you prefer, you can append the limiter to the existing method_decorators before adding the resource to your restful API.

ApiBase.method_decorators.append(limiter)
imbue_api.add_resource(ApiBase, settings.BASE_API_URL)

Upvotes: 2

Related Questions