Issue
I'm at a loss, i cant understand on how come DELETE requests are not coming through when POST, PUT and GET works just fine. And I'm pretty sure that I already did every bit configuration necessary for CORS to work. I'm using AngularJS and Flask-CORS extension
And here's my current work:
Angular Config:
angular.module('...' [...]).config(function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
Angular factory:
angular.module('...').factory('...'), function($http) {
return {
deleteElectronicAddress: function (partyId, contactMechanismId) {
return $http({
url: urlBase + 'party/' + partyId + '/contact-mechanism/' + contactMechanismId,
method: 'DELETE',
});
},
someMoreMethods: { ... }
}
}
My Flask codes, (I'm using the proposed app structure by Miguel Grinberg on his book Flask Web Development)
config.py
class Config:
...
CORS_HEADERS = 'Content-Type'
CORS_RESOURCES = {r"/api/*": {"origins": "*"}}
CORS_METHODS = ['GET', 'POST', 'DELETE', 'PUT', 'OPTIONS', 'HEAD']
...
project_folder/app/__init__.py:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.cors import CORS
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
CORS(app)
from .api_1_0 import api as api_1_0_blueprint
app.register_blueprint(api_1_0_blueprint, url_prefix='/api/v1.0')
return app
I'm currently using Flask-CORS v1.7.4.
project_folder/app/api/party_contact_mechanisms.py:
from datetime import date
from flask import jsonify
from .. import db
from ..models import PartyContactMechanism
from . import api
@api.route(
'/party/<int:party_id>' +
'/contact-mechanism/<int:contact_mechanism>', methods=['DELETE'])
def unlink_party_contact_mechanism(party_id, contact_mechanism):
"""Unlink the contact mechanism onto the party."""
party_contact = PartyContactMechanism.query \
.filter_by(party_id=party_id) \
.filter_by(contact_mechanism_id=contact_mechanism) \
.first()
party_contact.thru_date = str(date.today())
db.session.commit()
return jsonify(success=True)
I already tested this with httpie, both on my local machine and on another machine connected on the LAN, and it works just fine.
I'm running both angular and flask with 0.0.0.0 host configuration so that it can be accessible on the other machines connected on network.
here are my request and response headers when invoke from browser
REQUEST HEADERS:
OPTIONS /api/v1.0/party/32232/contact-mechanism/80667 HTTP/1.1
Host: 10.61.18.217:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://0.0.0.0:9000
Access-Control-Request-Method: DELETE
Connection: keep-alive
RESPONSE HEADERS:
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS, DELETE
access-control-allow-origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Content-Length: 0
Server: Werkzeug/0.9.6 Python/2.7.6
Date: Mon, 18 Aug 2014 07:20:18 GMT
here are the request and response headers when invoke from httpie:
REQUEST HEADERS:
DELETE /api/v1.0/party/32232/contact-mechanism/80667 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, compress
Content-Length: 0
Host: 10.61.18.217:5000
User-Agent: HTTPie/0.8.0
RESPONSE HEADERS:
HTTP/1.0 200 OK
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, POST, PUT
Access-Control-Allow-Origin: *
Content-Length: 21
Content-Type: application/json
Date: Mon, 18 Aug 2014 07:31:05 GMT
Server: Werkzeug/0.9.6 Python/2.7.6
{
"success": true
}
Solution
I got what i was doing wrong now,
actually there's another route on my project_folder/app/api/party_contact_mechanisms.py
file which i didn’t bother adding on my sample, since i thought its irrelevant (well i though wrong)
here it is:
@api.route(
'/party/<int:party_id>' +
'/contact-mechanism/<int:contact_mechanism>',
methods=['POST'])
@cross_origin(methods=['POST'])
def link_party_contact_mechanism(party_id, contact_mechanism):
"""Link the contact mechanism onto the party."""
party_contact = PartyContactMechanism(
party_id=party_id, contact_mechanism=contact_mechanism,
from_date=str(date.today()), thru_date=None
)
db.session.add(party_contact)
db.session.commit()
return jsonify({})
as you can see it has the the same route rule but with different method, in here its POST.
And before I used Flask-CORS v1.7 i was using v1.3, that explains the @cross_origin
decorator, since that's the only way to make your route CORS enabled (or if you want it on all your routes, you put it on your before_request
)
The thing i missed with the new version is, yes you can now make your whole app CORS enabled by initializing it, just like i did on my project_folder/app/__init__.py
, and yes you can still do specific routes via the `@cross_origin', but when you do, it overwrites the global config, and in my case I have two routes with the same rule but different methods and only one having the @cross_origin decorator and that's that root of the problem.
I just deleted it and it works just fine now. Be warned adding another @cross_origin
decorator on your other route wont fix it, it seems it only reads the first occurrence of it.
Answered By - cj cabero
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.