I\'ve developed a small write-only REST api with Flask Restful that accepts PUT request from a handful of clients that can potentially have changing IP addresses. My clients
I like to use a decoration to solve.
def cross_origin(origin="*"):
def cross_origin(func):
@functools.wraps(func)
def _decoration(*args, **kwargs):
ret = func(*args, **kwargs)
_cross_origin_header = {"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Headers":
"Origin, X-Requested-With, Content-Type, Accept"}
if isinstance(ret, tuple):
if len(ret) == 2 and isinstance(ret[0], dict) and isinstance(ret[1], int):
# this is for handle response like: ```{'status': 1, "data":"ok"}, 200```
return ret[0], ret[1], _cross_origin_header
elif isinstance(ret, basestring):
response = make_response(ret)
response.headers["Access-Control-Allow-Origin"] = origin
response.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
return response
elif isinstance(ret, Response):
ret.headers["Access-Control-Allow-Origin"] = origin
ret.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
return ret
else:
raise ValueError("Cannot handle cross origin, because the return value is not matched!")
return ret
return _decoration
return cross_origin
And then, Use decoration in your restful api.
class ExampleRestfulApi(Resource)
@cross_origin()
def get(self):
# allow all cross domain access
pass
@cross_origin(origin="192.168.1.100")
def post(self):
# allow 192.168.1.100 access
pass
Just an update to this comment. Flask CORS is the way to go, but the flask.ext.cors is deprecated.
use:
from flask_cors import CORS
To allow remote CORS requests on your web service api, you can simply initialize your flask restful API like this:
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"*": {"origins": "*"}})
api = Api(app)
This adds the CORS header to your api instance and allows a CORS request on every path from every origin.
I was facing the multiple types of CORS issue while connecting to my flask rest api from angular and tried almost all the approaches.
If you want to give access to all the websites without any restriction you can add below code in you app.py
script :
from flask_cors import CORS , cross_origin
cors = CORS(app, resources={r"/*": {"origins": "*"}})
this will work, but its recommended to have some security which you can always edit in origin
You're right, OPTIONS
method called every time before real request in browser. OPTIONS
response have allowed methods and headers. Flask automatically process OPTIONS
requests.
To get access for cross domain request you API must have Access-Control-Allow-Origin
header. It can contain specific domains, but if you want allow requests from any domains you can set it to Access-Control-Allow-Origin: *
.
To set up CORS for flask
you can look at one extension code or try use this extension: https://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py.
To set up CORS for flask-restful
look this pull requests: https://github.com/twilio/flask-restful/pull/122 and https://github.com/twilio/flask-restful/pull/131. But looks like flask-restful
does not support it by default yet.
How about this workaround:
from flask import Flask
from flask.ext import restful
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
#flask-sqlalchemy
db = SQLAlchemy(app)
#flask-restful
api = restful.Api(app)
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
import views
I took this from this tutorial. Works very good. actually, i think this is the best approach I've seen so far.
Returning {'Access-Control-Allow-Origin': '*'}
on each endpoint, doesn't seems to be efficient since you have to add it on every endpoint. a bit anoying..., at least for me.
I tried @cors.crossdomain(origin='*')
but, looks like it only works with GET request.