Reputation: 73
While trying the new CORS feature on flask-restful, I found out that the decorator can be only applied if the function returns a string.
For example, modifying the Quickstart example:
class HelloWorld(restful.Resource):
@cors.crossdomain(origin='*')
def get(self):
return {'hello': 'world'}
Throws:
TypeError: 'dict' object is not callable
Am I doing something wrong?
Upvotes: 7
Views: 4531
Reputation: 4360
I found that you can still use the decorator provided you return a string or JSON response (which is probably good practice for an API anyway). This is important if you want to do route-specific CORS headers, using the decorator makes life much easier. See this merged pull req for more information: https://github.com/flask-restful/flask-restful/pull/131
Here's an example:
from . import app
from flask_restful import reqparse, abort, Api, Resource
from flask.ext.cors import cross_origin
from datetime import datetime
from flask import jsonify
api = Api(app)
class DateTime(Resource):
@cross_origin(origins="http://localhost:63342*")
def get(self):
return jsonify({'DateTime': str(datetime.today())})
api_root = '/api/v1/'
api.add_resource(DateTime, api_root + 'DateTime')
If you're using flask-security, adding auth decorators had some weird behavior in my testing. I recommend assert current_user.is_authenticated
instead. If you are allowing credentials, make sure to CSRF protect.
Upvotes: 0
Reputation: 86
I recently came across this issue myself. @MartijnPieters is correct, decorators
can't be called on single methods of the view.
I created an abstract base class that contained the decorator
list. The class that consumes Resource
(from flask-restful) also inherits the base class, which is the class actually applying the decorator list to the view.
class AbstractAPI():
decorators = [cors.crossdomain(origin='*')]
class HelloWorld(restful.Resource, AbstractAPI):
#content
nope.
just add the decorator list to the parameters after you create the Api instance
api = Api(app)
api.decorators=[cors.crossdomain(origin='*')]
Upvotes: 7
Reputation: 1121884
The return value of the wrapped function is passed (as one argument) to flask.make_response()
; anything that a normal Flask view can return is acceptable. The decorator is essentially the same as this Flask snippet.
Because the Flask-restful Resource
is a subclass of flask.views.MethodView
you should really not put decorators directly on the methods here. As documented in Decorating Views you should list view decorators in a special class attribute, decorators
which is a list:
class HelloWorld(restful.Resource):
decorators = [cors.crossdomain(origin='*')]
def get(self):
return {'hello': 'world'}
and Flask will apply the view to the actual view method returned by HelloWorld.as_view()
, which is what Flask actually calls when dispatching the route to the view.
Applying them directly to the methods will only server to confuse the restful.Resource
dispatcher as it is expecting methods to return python datastructures suitable for encoding to JSON, which is not what cors.crossdomain()
returns anyway.
Upvotes: 0