Uploading a File JavaScript Fetch API to a Python Flask Backend with Authorization Header
Trying to upload a file from a web application, to a Python Flask backend, with authorization header. The straight forward way to upload a file to a Flask endpoint, with post request would like something like this:
<form action="https://url_to_endpoint" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
In this fashion, the Flask application will access the file through the request.files['file'] object. That’s it.
But, in the case at hand, the endpoint requires an access token in the Authorization header of the request.
Using the JavaScript fetch API, one can easily define the request headers, and submits the form via script, rather than the direct form submission.
Submitting the Form via Fetch – No Authorization Header, Yet.
So, the form tag will be changed to trigger a function, rather than submitting directly. I’ll keep it simple:
<form onsubmit="uploadMyFile(event)">
And with this in the uploadMyFile() function:
function uploadMyFile(event){
event.preventDefault();
return false;
}
Next, reading the form data, via a FormData() object, and sending the data using fetch:
function uploadMyFile(event){
event.preventDefault();
fd = new FormData(event.target);
fetch(url, {
method: 'POST',
body: fd
})
.then(....);
return false;
}
This actually does not work, because the request is missing the headers identifying its content-type, etc. Hence, we can get the headers from the FormData object, using getHeaders, so our fetch call would look something like this:
fetch(url, {
method: 'POST',
body: fd,
headers: fd.getHeaders
})
Now it works just like the form submission. What is needed then is to add the authorization header to the request. A handy way to do that is by appending the authorization header to the FormData headers:
const header = Object.assign({Authorization: 'Bearer ' + access_token}, fd.getHeaders);
Then pass this to the fetch call:
fetch(url, {
method: 'POST',
body: fd,
headers: header
})
To be fair, it took me to figure this out longer that I’d like to admit, but it’s here for future reference, despite it might not be the best solution.