I am trying to fetch rest api from XYZ provider inside python/flask webApp I used this as example/guide https://help.parsehub.com/hc/en-us/articles/217751808-API-Tutorial-How-to-get-run-data-using-Python-Flask
I dont have api key but auth token so this is code I am using and returns alldata
`from flask import Flask, render_template
import requests
import json
app = Flask(__name__)
#app.route('/')
def homepage():
headers = {
"Accept": "application/json",
"Authorization": "Bearer MYKEY"
}
r = requests.get(
'https://st1.example.com/restapi/domains/', headers=headers)
return json.loads(r.text)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
`
and this return all json data like this
json image
Id like to filter is to display only one part "domain" and "destination" but when adding code like this
r = requests.get(
'https://st1.example.com/restapi/domains/', headers=headers)
return json.loads(r.text)['destination']
I keep getting "Key error "destination" " or whatever I put in there
error
Your json returns data which is an array that contains destination. Assuming you want the first destination, try
return json.loads(r.text)['data'][0]['destination']
Or it coulde be written as:
results = json.loads(r.text)
return results['data'][0]['destination']
It seems like 'destination' is stored under 'data' in the JSON response. Also, you should just call r.json() instead of json.loads(r.text). You should also jsnoify your response.
from flask import Flask, render_template, jsonify
import requests
app = Flask(__name__)
#app.route('/')
def homepage():
headers = {
"Accept": "application/json",
"Authorization": "Bearer MYKEY"
}
r = requests.get(
'https://st1.example.com/restapi/domains/', headers=headers
)
destination = r.json()['data'][0]['destination']
return jsonify(destination), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
I have the following script written in python
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app, resources=r'/chat', headers='Content-Type')
#app.route("/chat")
def chat():
print(request)
request.get_data()
data = json.loads(request.data)
response = chatbot.get_response(str(data['message']))
response_data = response.serialize()
response = jsonify({'data': response_data})
return response
app.run(host="0.0.0.0", port=8900, debug=True)
I am calling this API from a JavaScript frontend running on http://localhost:8080
I am using Google Chrome and get the following error
Access to XMLHttpRequest at 'http://localhost:8900/chat/' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I also get the following the log message in the Python Console for each request
127.0.0.1 - - [19/Mar/2020 15:12:00] "?[33mOPTIONS /chat/ HTTP/1.1?[0m" 404 -
I am getting really frustrated because even if I change my code to
#app.route("/chat")
def chat():
print(request)
request.get_data()
data = json.loads(request.data)
response = chatbot.get_response(str(data['message']))
response_data = response.serialize()
response = jsonify({'data': response_data})
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'append,delete,entries,foreach,get,has,keys,set,values,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response
I still get the same error.
Can you try setting the headers like this instead?
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app, resources=r'/chat', headers='Content-Type')
#app.route("/chat")
def chat():
print(request)
request.get_data()
data = json.loads(request.data)
response = chatbot.get_response(str(data['message']))
response_data = response.serialize()
response = jsonify({'data': response_data})
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'append,delete,entries,foreach,get,has,keys,set,values,Authorization'
response.headers['Access-Control-Allow-Methods'] = 'GET,PUT,POST,DELETE,OPTIONS'
return response
app.run(host="0.0.0.0", port=8900, debug=True)
I have the following flask api, which just returns echo of its input:
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class query(Resource):
def get(self, a_string):
return{
'original': a_string,
'echo': a_string
}
api.add_resource(query,'/echo/<a_string>')
if __name__ == '__main__':
app.run()
Then, when I try to use python requests to make queries to my api:
import json
def query(text):
payload = {'echo': str(text)}
headers = {'content-type': 'application/x-www-form-urlencoded'}
r = requests.request("POST", 'http://127.0.0.1:5000', data=payload, headers=headers)
print(r)
#data = json.loads(r.text)
#return data
query('hi')
I keep getting:
<Response [404]>
Any idea of how to fix this issue? Interestingly when I go to my browser and do:
http://127.0.0.1:5000/echo/hi
I get:
{"original": "hi", "echo": "hi"}
But sending a POST to / with a payload of {"echo": whatever} is not at all the same as sending a GET to /echo/whatever. Your API expects the latter.
def query(text):
r = requests.get("http://127.0.0.1:5000/echo/{}".format(text))
Or, change your API so it does expect that:
class query(Resource):
def post(self):
a_string = request.form["echo"]
return {
'original': a_string,
'echo': a_string
}
api.add_resource(query, '/')
I am trying to retrieve data from server through a client using requests.post
task id id a random id
here is the server
from json import dumps
from werkzeug.exceptions import BadRequest
from flask import (
Flask,
Response,
request
)
from utils import get_random_id
app = Flask(__name__)
tasks = {
get_random_id(): {
"task": "write server mock",
"completed": True
}
#print(get_random_id())
}
#app.route(
'/tasks',
methods=['GET']
)
def list_tasks():
li = [
{
"id": task_id,
"task": values["task"],
"completed": values["completed"]
} for task_id, values in tasks.iteritems()
]
#print(li)
return Response(
dumps(li),
mimetype='application/json'
)
if __name__ == "__main__":
pass
Here is the client:
from flask import Flask,request
#importing server file that i made
import server
app = Flask(__name__)
app.testing = True
#app.route('/')
def index():
return request.url
response = app.test_client(server)
print(response)
I want to retrieve the posts in my python file all I manage to generate is response of the client
How do I get the table?
Do I use API Endpoints?
Please help me fix this error
You need to use some HTTP library for making a request.
Try http://docs.python-requests.org/en/master/
Example:
import requests
r = requests.get('{your server url}/tasks')
test_client method will create a client for you. And then you should use that client to query your server (either POST or GET or whatever). So you could use something like the following:
with server.test_client() as c:
resp = c.get('/tasks')
data = json.loads(resp.data)
print(data)
I am trying to make a cross origin request using jquery but it keeps being reject with the message
XMLHttpRequest cannot load http://... No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin ... is therefore
not allowed access.
I am using flask, heroku, and jquery
the client code looks like this:
$(document).ready(function() {
$('#submit_contact').click(function(e){
e.preventDefault();
$.ajax({
type: 'POST',
url: 'http://...',
// data: [
// { name: "name", value: $('name').val()},
// { name: "email", value: $('email').val() },
// { name: "phone", value: $('phone').val()},
// { name: "description", value: $('desc').val()}
//
// ],
data:"name=3&email=3&phone=3&description=3",
crossDomain:true,
success: function(msg) {
alert(msg);
}
});
});
});
on the heroku side i am using flask and it is like this
from flask import Flask,request
from flask.ext.mandrill import Mandrill
try:
from flask.ext.cors import CORS # The typical way to import flask-cors
except ImportError:
# Path hack allows examples to be run without installation.
import os
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.sys.path.insert(0, parentdir)
from flask.ext.cors import CORS
app = Flask(__name__)
app.config['MANDRILL_API_KEY'] = '...'
app.config['MANDRILL_DEFAULT_FROM']= '...'
app.config['QOLD_SUPPORT_EMAIL']='...'
app.config['CORS_HEADERS'] = 'Content-Type'
mandrill = Mandrill(app)
cors = CORS(app)
#app.route('/email/',methods=['POST'])
def hello_world():
name=request.form['name']
email=request.form['email']
phone=request.form['phone']
description=request.form['description']
mandrill.send_email(
from_email=email,
from_name=name,
to=[{'email': app.config['QOLD_SUPPORT_EMAIL']}],
text="Phone="+phone+"\n\n"+description
)
return '200 OK'
if __name__ == '__main__':
app.run()
Here is what worked for me when I deployed to Heroku.
http://flask-cors.readthedocs.org/en/latest/
Install flask-cors by running -
pip install -U flask-cors
from flask import Flask
from flask_cors import CORS, cross_origin
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
#app.route("/")
#cross_origin()
def helloWorld():
return "Hello, cross-origin-world!"
I've just faced the same issue and I came to believe that the other answers are a bit more complicated than they need to be, so here's my approach for those who don't want to rely on more libraries or decorators:
A CORS request actually consists of two HTTP requests. A preflight request and then an actual request that is only made if the preflight passes successfully.
The preflight request
Before the actual cross domain POST request, the browser will issue an OPTIONS request. This response should not return any body, but only some reassuring headers telling the browser that it's alright to do this cross-domain request and it's not part of some cross site scripting attack.
I wrote a Python function to build this response using the make_response function from the flask module.
def _build_cors_preflight_response():
response = make_response()
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers", "*")
response.headers.add("Access-Control-Allow-Methods", "*")
return response
This response is a wildcard one that works for all requests. If you want the additional security gained by CORS, you have to provide a whitelist of origins, headers and methods.
This response will convince your (Chrome) browser to go ahead and do the actual request.
The actual request
When serving the actual request you have to add one CORS header - otherwise the browser won't return the response to the invoking JavaScript code. Instead the request will fail on the client-side. Example with jsonify
response = jsonify({"order_id": 123, "status": "shipped"})
response.headers.add("Access-Control-Allow-Origin", "*")
return response
I also wrote a function for that.
def _corsify_actual_response(response):
response.headers.add("Access-Control-Allow-Origin", "*")
return response
allowing you to return a one-liner.
Final code
from flask import Flask, request, jsonify, make_response
from models import OrderModel
flask_app = Flask(__name__)
#flask_app.route("/api/orders", methods=["POST", "OPTIONS"])
def api_create_order():
if request.method == "OPTIONS": # CORS preflight
return _build_cors_preflight_response()
elif request.method == "POST": # The actual request following the preflight
order = OrderModel.create(...) # Whatever.
return _corsify_actual_response(jsonify(order.to_dict()))
else:
raise RuntimeError("Weird - don't know how to handle method {}".format(request.method))
def _build_cors_preflight_response():
response = make_response()
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add('Access-Control-Allow-Headers', "*")
response.headers.add('Access-Control-Allow-Methods', "*")
return response
def _corsify_actual_response(response):
response.headers.add("Access-Control-Allow-Origin", "*")
return response
OK, I don't think the official snippet mentioned by galuszkak should be used everywhere, we should concern the case that some bug may be triggered during the handler such as hello_world function. Whether the response is correct or uncorrect, the Access-Control-Allow-Origin header is what we should concern. So, it is very simple, just like the snippet bellow:
# define your bluprint
from flask import Blueprint
blueprint = Blueprint('blueprint', __name__)
# put this sippet ahead of all your bluprints
# blueprint can also be app~~
#blueprint.after_request
def after_request(response):
header = response.headers
header['Access-Control-Allow-Origin'] = '*'
# Other headers can be added here if needed
return response
# write your own blueprints with business logics
#blueprint.route('/test', methods=['GET'])
def test():
return "test success"
That is all~~
If you want to enable CORS for all routes, then just install flask_cors extension (pip3 install -U flask_cors) and wrap app like this: CORS(app).
That is enough to do it (I tested this with a POST request to upload an image, and it worked for me):
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes
Important note: if there is an error in your route, let us say you try to print a variable that does not exist, you will get a CORS error related message which, in fact, has nothing to do with CORS.
I resolved this same problem in python using flask and with this library.
flask_cors
in file init.py:
#pip install flask_cors
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource={
r"/*":{
"origins":"*"
}
})
and its all.
Reference: https://flask-cors.readthedocs.io/en/latest/
Improving the solution described here: https://stackoverflow.com/a/52875875/10299604
With after_request we can handle the CORS response headers avoiding to add extra code to our endpoints:
### CORS section
#app.after_request
def after_request_func(response):
origin = request.headers.get('Origin')
if request.method == 'OPTIONS':
response = make_response()
response.headers.add('Access-Control-Allow-Credentials', 'true')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
response.headers.add('Access-Control-Allow-Headers', 'x-csrf-token')
response.headers.add('Access-Control-Allow-Methods',
'GET, POST, OPTIONS, PUT, PATCH, DELETE')
if origin:
response.headers.add('Access-Control-Allow-Origin', origin)
else:
response.headers.add('Access-Control-Allow-Credentials', 'true')
if origin:
response.headers.add('Access-Control-Allow-Origin', origin)
return response
### end CORS section
All the responses above work okay, but you'll still probably get a CORS error, if the application throws an error you are not handling, like a key-error, if you aren't doing input validation properly, for example. You could add an error handler to catch all instances of exceptions and add CORS response headers in the server response
So define an error handler - errors.py:
from flask import json, make_response, jsonify
from werkzeug.exceptions import HTTPException
# define an error handling function
def init_handler(app):
# catch every type of exception
#app.errorhandler(Exception)
def handle_exception(e):
#loggit()!
# return json response of error
if isinstance(e, HTTPException):
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
else:
# build response
response = make_response(jsonify({"message": 'Something went wrong'}), 500)
# add the CORS header
response.headers['Access-Control-Allow-Origin'] = '*'
response.content_type = "application/json"
return response
then using Billal's answer:
from flask import Flask
from flask_cors import CORS
# import error handling file from where you have defined it
from . import errors
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes
errors.init_handler(app) # initialise error handling
Try the following decorators:
#app.route('/email/',methods=['POST', 'OPTIONS']) #Added 'Options'
#crossdomain(origin='*') #Added
def hello_world():
name=request.form['name']
email=request.form['email']
phone=request.form['phone']
description=request.form['description']
mandrill.send_email(
from_email=email,
from_name=name,
to=[{'email': app.config['QOLD_SUPPORT_EMAIL']}],
text="Phone="+phone+"\n\n"+description
)
return '200 OK'
if __name__ == '__main__':
app.run()
This decorator would be created as follows:
from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper
def crossdomain(origin=None, methods=None, headers=None,
max_age=21600, attach_to_all=True,
automatic_options=True):
if methods is not None:
methods = ', '.join(sorted(x.upper() for x in methods))
if headers is not None and not isinstance(headers, basestring):
headers = ', '.join(x.upper() for x in headers)
if not isinstance(origin, basestring):
origin = ', '.join(origin)
if isinstance(max_age, timedelta):
max_age = max_age.total_seconds()
def get_methods():
if methods is not None:
return methods
options_resp = current_app.make_default_options_response()
return options_resp.headers['allow']
def decorator(f):
def wrapped_function(*args, **kwargs):
if automatic_options and request.method == 'OPTIONS':
resp = current_app.make_default_options_response()
else:
resp = make_response(f(*args, **kwargs))
if not attach_to_all and request.method != 'OPTIONS':
return resp
h = resp.headers
h['Access-Control-Allow-Origin'] = origin
h['Access-Control-Allow-Methods'] = get_methods()
h['Access-Control-Max-Age'] = str(max_age)
if headers is not None:
h['Access-Control-Allow-Headers'] = headers
return resp
f.provide_automatic_options = False
return update_wrapper(wrapped_function, f)
return decorator
You can also check out this package Flask-CORS
You'd first need to install flask-cors. You can do this as follows:
pip install flask-cors
Once this is installed, you can use it in your Flask app as follows:
If you need to enable CORS for all routes:
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
If you want to enable CORS only for specific routes, you can pass the resources parameter to the CORS function.
For example,
CORS(app, resources={r"/api/*": {"origins": "*"}})
In this example, This code will enable CORS only for routes that start with /api/ and will allow requests from any origin. You can customize the resources parameter to match your needs.
For more information, please read the documentation
My solution is a wrapper around app.route:
def corsapp_route(path, origin=('127.0.0.1',), **options):
"""
Flask app alias with cors
:return:
"""
def inner(func):
def wrapper(*args, **kwargs):
if request.method == 'OPTIONS':
response = make_response()
response.headers.add("Access-Control-Allow-Origin", ', '.join(origin))
response.headers.add('Access-Control-Allow-Headers', ', '.join(origin))
response.headers.add('Access-Control-Allow-Methods', ', '.join(origin))
return response
else:
result = func(*args, **kwargs)
if 'Access-Control-Allow-Origin' not in result.headers:
result.headers.add("Access-Control-Allow-Origin", ', '.join(origin))
return result
wrapper.__name__ = func.__name__
if 'methods' in options:
if 'OPTIONS' in options['methods']:
return app.route(path, **options)(wrapper)
else:
options['methods'].append('OPTIONS')
return app.route(path, **options)(wrapper)
return wrapper
return inner
#corsapp_route('/', methods=['POST'], origin=['*'])
def hello_world():
...
If you can't find your problem and you're code should work, it may be that your request is just reaching the maximum of time heroku allows you to make a request. Heroku cancels requests if it takes more than 30 seconds.
Reference: https://devcenter.heroku.com/articles/request-timeout