I have one button in my react code and when I click it I should be able to download a file. I am using Python for backend(Not any framework). For react part I think this link explains what should be done. On button click, I should do an API call and on its return, I can render this IFrame component. Also, one other answer recommends responseType: 'blob' in axios call. My question is what should the backend do if we want to send a file over.Let's assume it just creates a file and returns it. I am actually using one third-party product which has its own API interface but an example with requests library would do.
def function_called_From_endpoint():
with open(path) as f:
return {'data': f }
Is something like this right?
So, I made it work this way:
def function_called_From_endpoint():
with open(file_path) as f:
data = f.read()
return {"data": data }
and on the front-end:
axios({
url: url, //your url
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.txt'); //or any other extension
document.body.appendChild(link);
link.click();
});
As suggested by https://stackoverflow.com/a/53230807/5573241. It worked well.
Related
I have a web application in which a map is being displayed. Right now all the markers are being passed via one API (http:3000/example) created in a node/express server. My goal is to read the user location that is retrieved from the frontend and use that as part of the query params to respond with only a selection of markers for the map based on algorithm written in python.
Main.js (Frontend)
async function callAPIAndUpdateMap(queryParams) {
const api = `http://localhost:3000/example?lat=${userCurrentPosition.lat}&lng=${userCurrentPosition.lng}${queryParams}`;
const listExampleEndpoint = new URL(api);
const response = await fetch(listExampleEndpoint);
exampleList = await response.json();
//todo: check if we need to remove all markers and put the updated new ones
let markers = drawMarkers();
new markerClusterer.MarkerClusterer({
map,
markers,
});
}
The function is called with params if selected by the user further down in the main.js file
function confirmFilter() {
appliedFilters = unconfirmedFilters;
let queryParams = ``;
appliedFilters.forEach((element) => {
queryParams += `&${element}=true`;
});
callAPIAndUpdateMap(queryParams);
let filterWrapper = document.getElementById("filter-wrapper");
filterWrapper.classList.add("hidden");
let filterButton = document.getElementById("filter-button");
let resetFilterIcon = document.getElementById("reset-filter");
if (appliedFilters.length != 0) {
filterButton.classList.add("active-map-button");
resetFilterIcon.classList.remove("hidden");
resetFilterIcon.classList.add("active-icon");
} else {
filterButton.classList.remove("active-map-button");
resetFilterIcon.classList.add("hidden");
resetFilterIcon.classList.remove("active-icon");
}
}
I am honestly a bit lost on how to read this request from a python file and then respond with data back. I have though about two different methods but I am not sure either would work.
Flask
I read the API get request using flask and respond directly in the python file
Python file triggered from Node.js
I read the get request from the Python file and apply the Algorithm and print a JSON dump that is triggered from a Node File
Python file that I am working with at the moment
import sys
import json
import requests
url = "http://3000/example"
r = requests.get(url, params=location)
data = r.json()
resp = {
"Response": 200,
"Message": "hello from Python File",
"Data":data
}
print(json.dumps(resp))
# using system module in python to send to node js
sys.stdout.flush()
Ok, I was really hoping that one of the various other questions on this topic would help me but I simply can't make this work! I'm relatively new to React and using API requests. I'm looking to upload an excel file from my React app and then process it in python using FastAPI as the interface.
I've followed the various tutorials / documentation approaches and I just get a 422 Unprocessable Entity Error!
In React, my event handlers look like this:
When file is selected, set the file in state:
onFileChange = (event) => {
this.setState({
uploadFile: event.target.files[0],
isFileSelected: true
});
};
When the "Upload" button is pressed, append to a FormData object and send via an axios request (Database is the axios object):
onUploadClick = async (event) => {
event.preventDefault()
var formData = new FormData();
formData.append(
"UploadFile",
this.state.uploadFile,
this.state.uploadFile.name
);
this.setState({isFileUploaded: true})
console.log(this.state.uploadFile)
const headers={'Content-Type': this.state.uploadFile.type}
await Database.post("/FileUpload",formData,headers);
};
And my FastAPI handler looks like this:
#app.post("/FileUpload")
async def FileUpload(file: UploadFile = File(...)):
# do some things...
Can someone please put me out my misery?
Your problem is due to the same reason as
How to send file to fastapi endpoint using postman
The name of the file variable in your fastapi endpoint has to match the name of the key to the file of your formdata. That is, your javascript should be like
formData.append(
"file",
this.state.uploadFile,
this.state.uploadFile.name
);
in order for your endpoint to be able to access the file parameter. Otherwise change the parameter's name (UploadFile in your case).
Part which is working fine :
I have made a <form> whose submit call makes an ajax request.Code for the same :
$.ajax({
type: 'POST',
url: '/uploaded_proto_file/',
data: formdata,
processData: false,
contentType: false,
success: function (data) {
console.log("in success")
console.log("data is --->"+data)
return;
},
error: function (data) {
console.log("in error")
return;
}
});
I am able to receive the call for the same on the function below. Now i need to send a file (which is in my document structure) that needs to auto downloaded in my browser. I execute this function based on this answer
def uploaded_proto_file(request):
with open(
'/Users/metal/Documents/test_pb2.py','rb') as text_file:
response = HttpResponse(FileWrapper(text_file.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=test_pb2.py'
return response
The above code wasn't working fine, so I debugged it and found this error on the filewrapper statement
Now I changed the solution a bit but the file sent back in response is not getting auto downloaded , it is getting printed in the console (as my success block in ajax function has console.log(data))
Changed solution :
with open(
'/Users/metal/Documents/test_pb2.py','rb') as text_file:
response = HttpResponse(text_file, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=test_pb2.py'
return response
As you can see above I removed FileWrapper and was atleast able to send the file back to ajax request. But the problem still persists as the file is not getting auto downloaded.
P.S. : I have also tried opening the file in different modes like 'r','rb'.
Any help would be appreciated !
You can't return a file to an ajax request and expect it to be downloaded. What you need is to separate into a few steps:
Your ajax request triggers the file creation process
Django puts that file somewhere where it can be downloaded and returns the URL to the file as ajax response
Your js response handler can now do two things:
Generate a button in the HTML for the user to click and download the file (using the URL from the response)
Create the button and auto-click it (call .click() on it) and then delete it again. A bit like in this example
I am trying to upload an image to Etsy through the API. However, the example on their website is given in PHP which I don't know how to code. I only know how to work with Python. On their website it says:
Image uploads can be performed using a POST request with the Content-Type: multipart/form-dataheader, following RFC1867.
Their example which is in PHP
// You must define the constants OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET
// You must also assign values to the variables $access_token, $access_token_secret,
// $listing_id and $filename, and $mimetype.
// Your image file is assumed to be in the same directory as this code.
$oauth = new OAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
$oauth->enableDebug();
$oauth->setToken($access_token, $access_token_secret);
try {
$source_file = dirname(realpath(__FILE__)) ."/$filename";
$url = "https://openapi.etsy.com/v2/listings/".$listing_id."/images";
$params = array('#image' => '#'.$source_file.';type='.$mimetype);
$oauth->fetch($url, $params, OAUTH_HTTP_METHOD_POST);
$json = $oauth->getLastResponse();
print_r(json_decode($json, true));
} catch (OAuthException $e) {
// You may want to recover gracefully here...
print $oauth->getLastResponse()."\n";
print_r($oauth->debugInfo);
die($e->getMessage());
}
In API doc it says
HTTP Method = POST
URI = /listings/:listing_id/images
This is what I have so far in Python:
client_secret=client_secret,resource_owner_key=resource_owner_key,resource_owner_secret=resource_owner_secret)
url = 'https://openapi.etsy.com/v2/listings'
payload = {'listing_id':'2343432434', 'images': :('test1.jpg', open('test1.jpg', 'rb'), 'image/jpeg')}
result = etsy.post(uri, params=payload)
When I run this code I get an 403 error. How can I fix my code so that it functions correctly? I have looked at other examples and just can't seem to make it work.
I want to create a Flask error handler that returns a JSON response if the request was from JavaScript but returns a redirect otherwise. I tried using request.is_xhr, but it is false even for JavaScript requests. How can I check if the request is from JavaScript?
#app.errorhandler(Exception)
def unhandled_exception(error):
if request.is_xhr:
return flask.jsonify(error='yes')
return redirect(url_for('error'))
There is no standard or reliable way to detect if a request comes from a particular source, such as JavaScript.
is_xhr was only true when a certain header was set by some JavaScript libraries, such as jQuery. The header is not sent by most JavaScript. is_xhr has been deprecated for that reason.
You can check the Accept header to see if the client is asking for application/json, but that too is unreliable.
if request.is_xhr or request.accept_mimetypes.accept_json:
return jsonify(...)
return redirect(...)
Answer by #davidism makes sense. is_xhr was only true when a certain header was set by some JavaScript libraries. So, I have set header 'X-Requested-With' to 'XMLHttpRequest' manually in '$httpProvider' config in AngularJs. This ensures that on the back end I will get 'is_xhr' true for AJAX request.
app.config([
'$httpProvider',
function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
var interceptor = [
'$q',
'$rootScope',
function ($q, $rootScope) {
'responseError': function (rejection) {
if(rejection.status != undefined && rejection.status != 'undefined') {
window.location.href = '/error';
}
}
};
return service;
}
];
$httpProvider.interceptors.push(interceptor);
}
]);
Rather than tie my app to a non-standard header I added an Accept: header to my Javascript instead:
let req = new XMLHttpRequest();
req.open('POST', location);
// signal back-end to return json instead of rendering a full page:
req.setRequestHeader('Accept', 'application/json');
req.send(…);
And in my Python:
# if an ajax-like request, return json instead of html
if request.accept_mimetypes.best == 'application/json':
log.debug('client prefers json, skipping page render.')
return jsonify(status='errror', detail='…')
This should handle other use cases as they come up.
If the request is from a javascript/jquery code, is it most certainly from a browser so you can check the flask.request.user_agent object which is a instance of werkzeug.useragents.UserAgent to verify that.