I am using
Python 3.6.3
Flask==1.0.2
Flask-Cors==3.0.7
Flask-RESTful==0.3.7
for making an API which is used to collect tiff image using post method and save it locally.
api = Api(app)
CORS(app)
class CatchImage(Resource):
#cross_origin(supports_credentials=True)
def post(self):
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
if which_extenstion(filename) != "tiff":
return json.dumps({
"id": None,
"error": "Unsupported file type"
})
else:
unique_id, folder_path, save_path = get_unique_id(filename)
try:
file.save(save_path)
except FileNotFoundError:
LookupError("no uploads folder")
convert_jpg_save(save_path)
jpg_image_path = get_jpg_image_path(folder_path)
img = [
url_for("send_image", filename=image)
for image in jpg_image_path
]
return jsonify({
"filename ": file.filename,
"id": unique_id,
"urls": img,
"error": None
})
return json.dumps({"error": "no file"})
api.add_resource(CatchImage, '/api/sendimage')
I have tried the API using Postman which is working very fine. But when I try to access the API from Browser I get this
POST http://127.0.0.1:5000/api/sendimage 400 (BAD REQUEST)
The code for the same is below, which generated by Postman.
var form = new FormData();
form.append("file", "/home/blue/Templates/test.tiff");
var settings = {
"async": true,
"crossDomain": true,
"url": "http://127.0.0.1:5000/api/sendimage",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"Postman-Token": "4fdcc138-5567-4c4d-8f7d-8967d45b3c2a"
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}
$.ajax(settings).done(function (response) {
console.log(response);
});
I do think this has to do with CORS or setting some error which I not able to figure out. I would like to understand what is the probable cause of the problem and it's mostly likely solutions.T hanks in advance for your time – if I’ve missed out anything, over- or under-emphasized a specific point let me know in the comments.
400 (BAD REQUEST) means the data sent is not the data expected by the server. I do not think it is CORS related.
I would recommend to use pdb in your post function to find where the response is thrown.
import pdb; pdb.set_trace()
According to jQuery documentation, you must declare the data type:
$.ajax({
type: 'POST',
url: url,
data: data,
success: success,
dataType: dataType
});
possibly adding this help:
dataType: "json",
References:
Getting 400 bad request error in Jquery Ajax POST
Jquery ajax post request not working
Related
I have deployed my App on Vertex AI endpoint. The endpoint is created successfully and I am getting "Active" status. But when I try to invoke the endpoint, I am getting the following error:
{
"error": {
"code": 500,
"message": "Prediction failed. Please contact cloudml-feedback#google.com",
"status": "INTERNAL"
}
}
POST Request URL: https://us-central1-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/us-central1/endpoints/${ENDPOINT_ID}:predict
Header: I am passing the required header i.e., Content-Type: application/json and Authorization token.
Body:
{
"instances": [{
"image_path": "https://github.com/naqishah13/multilabelimages/blob/main/movie-poster-1.jpg?raw=true"
}
]
}
Here is my flask code that I am using for prediction:
#app.route('/get_movie_genres/', methods=['POST'])
def main():
request_json = request.get_json()
request_instances = request_json['instances']
image_path = request_instances[0]['image_path']
predicted_genres = predict_(image_path)
output = {'predictions':
[
{
'predicted_genres' : prediction
}
]
}
return jsonify(output)
I have saved some images on github and I am using those images (via github path) in order to do the movie genre prediction.
Am I doing something wrong? what might be causing the issue?
here is the line of code returning the error message from flask api
return jsonify(message='wrong username or password'),400
reading it from here in react js
axios
.post("http://127.0.0.1:5000/authentication/login", body)
.then((res) => {
console.log(res)
})
.catch((error) => {
console.log(error);
});
and this is what i see in the console
{"message":"Request failed with status code 400","name":"Error","stack":"Error: Request failed with status code 400\n at createError (http://localhost:3000/static/js/1.chunk.js:854:15)\n at settle (http://localhost:3000/static/js/1.chunk.js:1075:12)\n at XMLHttpRequest.handleLoad (http://localhost:3000/static/js/1.chunk.js:329:7)","config":{"url":"http://127.0.0.1:5000/auth/login","method":"post","data":"{\"phone\":\"\",\"password\":\"\"}","headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1}}
The results doesn't not contain the custom message 'wrong username or password'
have actually gotten the solution, something simple
the error data can be accessed from
console.log(error.response.data);
flask by default returns html page instead of json when error is thrown. to make run return normal json as with 200's responses write this in your flask app:
from werkzeug.exceptions import HTTPException
#app.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
print(e)
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
response.content_type = "application/json"
return response
then for example for such return in flask
...
return json.dumps(str(e)), 409
and then you can catch in your js:
...
}).then(function(response) {
...
}).catch((error) => {
console.log(error.response.data); // will log your error as string
})
I have a React app that makes a POST request to a Flask backend. The POST request is designed to alter some data in a database and send back a calculated value. Everything seems to work on the Flask side except for the response. The response I get from Flask is:
Response { type: "cors",
url: "http://127.0.0.1:3122/update",
redirected: false,
status: 200, ok: true, statusText: "OK", headers: Headers, bodyUsed: false }
I'm not sure what I'm doing wrong. In my Flask code, I use in the function decorated by #app.after_request
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,text/plain')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
and also the flask_cors package to allow for CORS from the client side.
app = Flask(__name__)
app.config['DEBUG'] = True
api = CORS(app, resources={r"/*": {"origins": "*"}})
I've also tried to set the mimetype in my response from Flask to be text/plain so a pre-flight request isn't invoked.
resp = Response(response=calculation_json,
status=200,
mimetype='text/plain')
The POST request code is:
(async () => {
const rawResponse = await
fetch(url, {
method: 'POST',
headers: {
'Accept': 'text/plain',
'Content-Type': 'text/plain'
},
body: jsonData
});
const response = await rawResponse;
if (response.status >= 200 && response.status < 300) {
console.log(response);
return Promise.resolve(response)
} else {
this.props.form.resetFields();
return Promise.reject(new Error(response.statusText))
}
In case if for client side of your application you have use create-react-app, you can add a proxy configuration in package.json file.
"proxy": {
"/apiRoute": {
"target": "http://127.0.0.1:3122"
},
},
The /apiRoute is the name of the routes (GET, POST, PUT..) you had defined in Flask. So i would suggest to make a pattern in Flask for all routes like /api/**, so in package.json instead of adding all routes, you can something like below
"proxy": {
"/api/*": {
"target": "http://127.0.0.1:3122"
},
},
You would have to change your response code such that it returns data not just regular http 200. In this case looks like you want Json back.
See the examples:
Return JSON response from Flask view
I'm working on a flask web application in which the client posts data to the server in the form of:
{
"sess_id" : 1 ,
"annotations" :
[ {"tag_start" : "TIME","tag_end" : "TIME","tag" : "YOUR_TAG"}, {"tag_start" : "TIME","tag_end" : "TIME","tag" : "YOUR_TAG"}, {"tag_start" : "TIME","tag_end" : "TIME","tag" : "YOUR_TAG"}]
}
Here is the full Ajax post...
$.ajax({
url: 'http://127.0.0.1:5000/api/saveannotation',
type: 'POST',
headers: {'Content-Type' : 'application/json'},
data: {'sess_id' : $('#sessionid_area').val(),
'annotations': JSON.parse(annotations)},
success: function(data) { alert(data.status); }
});
so I can even see this on the api side, which is defined as such:
#sessionapis.route('/saveannotation', methods=['GET', 'POST'])
#login_required
def save_annotation():
rData = request.data
if request.method == 'GET':
return jsonify({'status' : 'success GET'})
else:
return jsonify({'status' : 'success'})
The issue is that data is a "byte" type, not a dict. I also can't call request.json or request.get_json(silent=True), it returns "400 bad request".
Here is a sample of what is in request.data:
b'sess_id=1&annotations%5B0%5D%5Btag_start%5D=2...
it appears to be url encoded for some reason. Values is also empty. If I choose to do something wild, like leave out the content-type = json; I can get a dict-like thing, but I have to access it very oddly. I don't get individual objects, but rather just flat access to all properties.
Any thoughts on how to just get the json parsed into a reasonable object?
Thanks for any hints!
Just passing a content-type header of JSON doesn't actually make the data itself into JSON. You either need to do that yourself, or tell jQuery to do so.
$.ajax({
url: 'http://127.0.0.1:5000/api/saveannotation',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({'sess_id' : $('#sessionid_area').val(),
'annotations': JSON.parse(annotations)}),
success: function(data) { alert(data.status); }
});
Now your data will be in JSON format and you can get it as a Python dict with request.get_json().
I have the following code which retrieves values from a simple 3 input form:
//retrieves data from a form
var $form = $( this ),
prgname= $form.find('input[name="prg"]').val(),
startDate = $("#startdate").datepicker({ dateFormat: 'yy-mm-dd' }).val(),
endDate = $("#enddate").datepicker({ dateFormat: 'yy-mm-dd' }).val();
The following code sends the request to the server:
var request = $.ajax({
url: "/prg/",
type: "post",
data: JSON.stringify({prg: prgname, start:startDate, end:endDate}),
contentType: 'application/json',
dataType: 'json',
success: function() {},
error: function (jqXHR, textStatus, errorThrown){};
on the server end using python and webapp2 Im doing the following, (here is where I am unsure of things)
import json
class PrgHandler(webapp2.RequestHandler):
def post(self):
prg= cgi.escape(self.request.POST['prg'])
start_date = cgi.escape(self.request.POST['start'])
end_date = cgi.escape(self.request.POST['end'])
#some code to write to db here
....
#if successful return a success message
if success:
success_msg = [{'class': 'success', 'msg': 'Successfully saved to the database'}]
else:
success_msg = [{'class': 'error', 'msg': 'Could not saved to the database'}]
data_string = json.dumps(success_msg)
self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
self.response.write(data_string)
When I get the response it is skipping the success function and going directly to the error.
Logging the error values im not getting any thing meaningful:
the error is:
The text status is:error
The jqXHR is:[object Object]
Chrome's console is giving me the error:
Resource interpreted as Document but transferred with MIME type application/json:
I looked that up and the solutions on SO did not work, I think this is an error with the server side code:
self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
If I comment out the above line I get no error in chrome and I just get back the response on a blank page with the correct values in the following format:
[{"msg": "Successfully saved to the database", "class": "success"}]
In the above case it does save to the database so I cannot seem to find anything wrong except for the header and simply don't know how to proceed!
EDIT
The error it seems is from the server side I had removed the following line:
event.preventDefault();
from my script and it caused all the problems now at least Im getting a clear indication of where the problem is. It's from incorrectly getting the posted data, how would I do it the correct way? I tried the following:
json_data = self.request.GET.items()
decoded = json.loads(json_data)
but Im getting a TypeError: expected string or buffer on the following line:
json_data = self.request.GET.items()
Have a look in your debugger. You receive a JSON string in your post (webapp2 multidict). You have to decode this string using json.loads, resulting in a python object.
Here is my jquery code to send and receive json :
function gaeQuery(request) {
var url = "/query";
var payload = {'jsondata' : JSON.stringify(request)};
$.post(
url,
payload,
function(response) {
procesResponse(response);
}, // succes response callback
'json', // response contains JSON content, and will be decoded in a js object
{
contentType: "application/json;charset=utf-8", // send JSON content
timeout: 20000,
tryCount: 0,
retryLimit: 3, // max 3 retries
error: function(xhr, textStatus, errorThrown) { // error handling callback
if (textStatus === 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) { //try again until retryLimit
$.ajax(this);
return;
}
alert('We have tried ' + this.retryLimit + ' times and it is still not working. We give in. Sorry.');
return;
}
if (xhr.status === 500) { // internal server error
alert('Oops! There seems to be a server problem, please try again later.');
}
else {
alert('Oops! There was a problem, sorry.'); // something went wrong
}
}
}
);
}
OK so I managed to figure this out and thought I will post the answer that worked for me to help anyone looking for this information because the webapp2 docs are not that helpful when it comes to 'getting' posted json data.
on the client side I did the following:
var request = $.ajax({
url: "/some/url/",
type: "POST",
data: JSON.stringify([{someval: val1, someval2:val2, someval3:val3}]),
contentType: "application/json",
dataType: 'json',
beforeSend: function() {
$('#loading-div').show();
},
complete: function(){
$('#loading-div').hide();
},
success: function(response, textStatus, jqXHR){}
});
The reason I couldnt figure out the problem straight away was because of the following line which I deleted along with some commented out line which prevented the page from redirecting after posting. This was the source of all the weird, unrelated and unhelpful error messages:
event.preventDefault();
on the server side to get the json data being posted to appengine do the following:
jdata = json.loads(cgi.escape(self.request.body))
for vals in jdata:
val1 = vals['someval']
val2 = vals['someval2']
val3 = vals['someval3']
The above was the root of the problem I wasn't doing it right and without the previous line on the client side there was no way to figure it out.
Anyways once you have the data do whatever processing you need to do with it and once you are done and need to send back a json response add the following lines:
//the data would look something like this
data = {'return_value': val1, 'return_value2': val2,
'return_value3': val3, 'return_value4': val4}
return_data = json.dumps(data)
self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
self.response.write(return_data)
Almost forgot on the client side again to access the variables sent back from the server with jquery its very straight forward...do something like:
success: function(response, textStatus, jqXHR){
console.log(response.return_value);
console.log(response.return_value2);
console.log(response.return_value3);
}
Hope this will help someone seeking this information.