flask-restful - resource class for current request
Instead of inheriting from flask_restful.Resource
your want to inherit all from a custom resource
class MyResource(flask_restful.Resource):
def dispatch_request(self, *args, **kwargs):
try:
return super(MyResource,self).dispatch_request(*args, **kwargs)
except Exception as ex:
setattr(ex, "_raised_by", self)
raise ex
and then you can use the exception handler
def log_exception(sender, exception, **extra):
_raised_by = getattr(exception, "_raised_by", None)
if _raised_by:
print(_raised_by)
property("URL: {}, Exception: {}".format(request.url, type(exception).__name__))
Here is complete code I tried
from flask import request, Flask
import flask_restful
app = Flask(__name__)
api = flask_restful.Api(app)
class MyResource(flask_restful.Resource):
def dispatch_request(self, *args, **kwargs):
try:
return super(MyResource,self).dispatch_request(*args, **kwargs)
except Exception as ex:
setattr(ex, "_raised_by", self)
raise ex
# MyResource = flask_restful.Resource
class SomeResource(MyResource):
def get(self):
raise Exception("Not implemented")
def log_data(self):
# log all body params
return request.get_json()
class Login(MyResource):
def post(self):
raise Exception("Not implemented")
def log_data(self):
# log selected body params
return {'login': request.get_json()['login'], 'password': 'HIDDEN!'}
from flask import got_request_exception, request
api.add_resource(Login, '/login')
api.add_resource(SomeResource, '/some')
def log_exception(sender, exception, **extra):
_raised_by = getattr(exception, "_raised_by", None)
if _raised_by:
print(_raised_by)
property("URL: {}, Exception: {}".format(request.url, type(exception).__name__))
got_request_exception.connect(log_exception, app)
if __name__ == '__main__':
app.run(debug=True)
Edit-1: 5th Aug
As commented by @jbet, in case one wants to get the processing class always a cleaner option would be to use the MyResource
as below
from flask import g
class MyResource(flask_restful.Resource):
def dispatch_request(self, *args, **kwargs):
g.processed_by = self
return super(MyResource,self).dispatch_request(*args, **kwargs)
I could not find a nice way to get access to your object once the logging method had been called by signals.
If you were willing to handle all possible cases, you could create your own custom exceptions that call the log_data method on your class.
Instead, I opted to handle logging myself in a base class. Simple example for you, I just used print functions, but you could call app.logging.info instead.
from flask import Flask, request
import flask_restful
app = Flask(__name__)
api = flask_restful.Api(app)
class MyCustomResource(flask_restful.Resource):
def get(self):
try:
self.my_get()
except Exception as exception:
# Will catch all errors in your subclass my_get method
print("exception caught")
print(request.url)
print(type(exception).__name__)
print(self.log_data())
# Re-raise if you want (or not)
raise exception
def my_get(self):
# Python equivalent of virtual method
raise NotImplementedError()
def log_data(self):
# Python equivalent of virtual method
raise NotImplementedError()
class SomeResource(MyCustomResource):
def my_get(self):
# Example unknown error occurs here
raise Exception("error!")
return "some data"
def log_data(self):
# Called by parent
return "some logging data for the object"
api.add_resource(SomeResource, "/")
If you wanted to dig deeper into the flask restful source you could also monkey patch (or build your own package) whatever method is calling get/post.