I have a static file with some jQuery that access an API built with connexion. Unfortunatelly, the browser requires CORS to be enable in order to access the API. I couldn't find a way of adding fields to the headers response nor a module or option to do that, so I'm not sure on what to do about.
Another possible workaround would be if I could just serve this static code with Connexion, I found lots of solutions for Flask but nothing that worked with Connexion
Output of the commands:
python --version
Hi @ernanirst - I believe you can access the underlying flask 'app' object and enable CORS the same way you'd do it with a flask service like so:
import connexion
from connexion.resolver import RestyResolver
from flask_cors import CORS
app = connexion.App(__name__)
CORS(app.app)
app.add_api('api.yaml', resolver=RestyResolver('seaiceservices.api'))
@ernanirst see #50 for answers/discussion, using flask-cors
looks good enough for me.
Re-opening, as we should add a section regarding CORS on http://connexion.readthedocs.io/en/latest/cookbook.html
See my PR #358.
Thanks a lot, I've tried something very similar which did not work, but this worked fine. I suggest that you add this to the docs because I looked there and found nothing. Thanks again.
I'm trying to use flask cors with connexion
#!/usr/bin/env python3
import config
import connexion
import logging
import logging.handlers
from connexion.resolver import RestyResolver
from flask.logging import default_handler
from flask_jwt_extended import JWTManager
from flask_cors import CORS
def create_app():
app = connexion.FlaskApp(__name__, specification_dir='swagger/')
app.add_api('mapmybook.yaml', validate_responses=True, strict_validation=True, resolver=RestyResolver('api'))
app.app.config.from_object(config.DevelopmentConfig)
app.app.logger.addHandler(create_file_handler())
jwt = JWTManager(app.app)
return app.app # return <Flask> object
def create_file_handler():
...
return rfh
if __name__ == '__main__':
app = create_app()
CORS(app.app)
app.run(port=5000)
Yet when I send a request
curl 'http://127.0.0.1:5000/v1.0/login' -X OPTIONS -H 'Pragma: no-cache' -H 'Access-Control-Request-Method: POST' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.9' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.36' -H 'Accept: */*' -H 'Cache-Control: no-cache' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Access-Control-Request-Headers: content-type' --compressed
I get
Failed to load http://127.0.0.1:5000/v1.0/login: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access
What else do I have to set to make this work with application/json content type?
Just a stab in the dark. But add the resources
argument, for example:
...
CORS_RESOURCES = {r"/v1/*": {"origins": "*"}, r"/v1.0/*": {"origins": "*"}, r"/v1.1/*": {"origins": "*"}}
CORS(app.app, resources=CORS_RESOURCES)
...
Seems @cross_origin
decorator solves the problem, but CORS(app)
alone is not working.
Just for reference, for simple use cases you can simply add the required headers yourself to all responses. There is two ways to achieve this.
Using a custom middleware:
class CorsHeaderMiddleware(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
def custom_start_response(status, headers, exc_info=None):
# append whatever headers you need here
headers.append(('Access-Control-Allow-Origin', '*'))
headers.append(
('Access-Control-Allow-Headers', 'X-Requested-With')
)
headers.append(('Access-Control-Allow-Methods', 'OPTIONS'))
return start_response(status, headers, exc_info)
return self.app(environ, custom_start_response)
connexion_app = connexion.FlaskApp(__name__, specification_dir='.')
connexion_app.add_api('specification.yml')
connexion_app.app.wsgi_app = CorsHeaderMiddleware(connexion_app.app.wsgi_app)
Using Flask's after_request hook:
def set_cors_headers_on_response(response):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'X-Requested-With'
response.headers['Access-Control-Allow-Methods'] = 'OPTIONS'
return response
connexion_app = connexion.FlaskApp(__name__, specification_dir='.')
connexion_app.add_api('api_specification.yml')
connexion_app.app.after_request(set_cors_headers_on_response)
While the Flask
hook approach is a bit shorter, the WSGI middleware will keep working even when switching to a different backend like tornado
or gevent
later.
Most helpful comment
Hi @ernanirst - I believe you can access the underlying flask 'app' object and enable CORS the same way you'd do it with a flask service like so: