Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable CORS for particular routes. #176

Closed
rajaravivarma-r opened this issue Dec 23, 2016 · 7 comments
Closed

Enable CORS for particular routes. #176

rajaravivarma-r opened this issue Dec 23, 2016 · 7 comments
Labels

Comments

@rajaravivarma-r
Copy link

We should be able to mark a route as CORS enabled. The route should be able to intercept any 'OPTIONS' request and handle it as configured.

I am thinking of a decorator like,

@cors(allow_headers=['Content-Type', 'Expires'], allow_methods=['POST', 'PUT'], allow_origin=['foo.com', 'bar.com'])
@app.route('/users')
def users():
    return User.all().select(User.id, User.name)

I put up something as a quick hack for one such use case.

def allow_cors():
    response.headers['Access-Control-Allow-Origin'] = '*'

def set_allowed_http_methods():
    response.headers['Access-Control-Allow-Methods'] = ', '.join(['POST', 'PUT', 'PATCH', 'GET', 'HEAD', 'OPTIONS'])

def set_allowed_headers():
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type'

def set_json_response():
    response.headers['Content-Type'] = 'application/json; charset=utf-8'

def set_plain_text_response():
    response.headers['Content-Type'] = 'text/plain'

@app.route("/hero/<int:id>", methods=["options", "put", "patch", "get"])
def hero_show(id):
    id = int(id)
    allow_cors()
    if request.method in ['options']:
        set_plain_text_response()
        set_allowed_http_methods()
        set_allowed_headers()
        return '{}'

    set_json_response()
    if request.method in ['put', 'patch'] and id:
        Hero.where(lambda h: h.id == id).update(name=request.params.name)
        db.commit()
    # import ipdb
    # ipdb.set_trace()
    hero = Hero.get(id)
    import json
    return json.dumps({'id': hero.id, 'name': hero.name})

I would like to contribute this feature, if you like. Please give your inputs.

@gi0baro
Copy link
Member

gi0baro commented Dec 26, 2016

Hi @rajaravivarma-r, I usually use a Handler for cors (and I think it's the correct way to do it in weppy):

from weppy import response
from weppy.handlers import Handler

class CORS(Handler):
    def on_start(self):
        response.headers["Access-Control-Allow-Origin"] = "my.domain.tld"
        response.headers["Access-Control-Allow-Credentials"] = "true"
        response.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST, PUT, PATCH, DELETE"
        response.headers["Access-Control-Allow-Headers"] = "Origin, Content-Type, Accept, Authorization"

Then you can add it to all routes or just a specific route:

#: common
app.common_handlers = [CORS()]
#: single
@app.route('/route', handlers=[CORS()])

I can add a customizable handler like this one inside weppy, and it will be a Pipe since handler are deprecated in the next version.

Regarding the options request, I think it would be better to have a catch-all route for options (I usually do this):

@app.route('/<any:p>', methods='options', handlers=[CORS()])
def _options(p):
    return ""

@rajaravivarma-r
Copy link
Author

Thank you @gi0baro, I didn't know this approach. I couldn't find it in the documentation.

@gi0baro
Copy link
Member

gi0baro commented Dec 27, 2016

@rajaravivarma-r Yes, I'm currently rewriting some parts of the documentation for the next version which should explain these stuffs :)

@guy881
Copy link

guy881 commented Dec 18, 2017

Now you should use a Pipe for this purpose, since handlers are deprecated.

from weppy import Pipe, response


class CORS(Pipe):
    def open(self):
        response.headers["Access-Control-Allow-Origin"] = "example.com"
        response.headers["Access-Control-Allow-Credentials"] = "true"
        response.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST, PUT, PATCH, DELETE"
        response.headers["Access-Control-Allow-Headers"] = "Origin, Content-Type, Accept, Authorization"

and in you app.py:

app.pipeline = [db.pipe, CORS()]

@felipebastosweb
Copy link

Hello, what allow origin config to enable ALL sites because I need to use mobile apps with weppy webapps.

@gi0baro
Copy link
Member

gi0baro commented Jul 30, 2018

@felipebastosweb usually you don't need CORS on mobile apps, but only for ajax requests.
Btw, if I understood correctly your question, you can always apply a Pipe on every application route:

from weppy import Pipe, response


class CORS(Pipe):
    def open(self):
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers["Access-Control-Allow-Credentials"] = "true"
        response.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST, PUT, PATCH, DELETE"
        response.headers["Access-Control-Allow-Headers"] = "Origin, Content-Type, Accept, Authorization"

app.pipeline = [CORS()]

@felipebastosweb
Copy link

I needed with Ionic3 android platform and CORS pipeline is working.
Thanks!!!

@gi0baro gi0baro closed this as completed Nov 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants