Uploading an excel file to FastAPI from a React app - python

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).

Related

Reading Query Params of Get request in python file

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()

Download file functionality for react and python app

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.

Identify if Flask request is from JavaScript or not

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.

Connecting Python Backend to Android APP

How to use python as a backend for an Android App that is built using C#? The Python Backend is written using the Flask framework. The Android app is built using xamarin.
No matter what type of technology your server or the client use if they can communicate with each other using some sort of standard "protocol".
There are many ways to communicate both sides (client and server) like sockets, xml, json, etc. They just need to understand each other.
In your particular case I suggest to build a REST or RESTful API (https://flask-restful.readthedocs.org/en/0.3.3/) on the server and a REST client library on the client.
There are many ways and libraries to call REST APIs from C#:
The built-in method would be using HttpWebRequest as you can see on this link:
private async Task<JsonValue> FetchWeatherAsync (string url)
{
// Create an HTTP web request using the URL:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create (new Uri (url));
request.ContentType = "application/json";
request.Method = "GET";
// Send the request to the server and wait for the response:
using (WebResponse response = await request.GetResponseAsync ())
{
// Get a stream representation of the HTTP web response:
using (Stream stream = response.GetResponseStream ())
{
// Use this stream to build a JSON document object:
JsonValue jsonDoc = await Task.Run (() => JsonObject.Load (stream));
Console.Out.WriteLine("Response: {0}", jsonDoc.ToString ());
// Return the JSON document:
return jsonDoc;
}
}
}
But I don´t recommend it if you don´t want your app to be full of crap (boiler plate code) everywhere.
A helper library could be, for example, RESTSharp. It allows you to build REST calls easily and cast the response to your typed objects. Here´s and example:
var client = new RestClient("http://example.com");
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("id", "123"); // replaces matching token in request.Resource
// easily add HTTP Headers
request.AddHeader("header", "value");
// add files to upload (works with compatible verbs)
request.AddFile(path);
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
// or automatically deserialize result
// return content type is sniffed but can be explicitly set via RestClient.AddHandler();
RestResponse<Person> response2 = client.Execute<Person>(request);
var name = response2.Data.Name;
// easy async support
client.ExecuteAsync(request, response => {
Console.WriteLine(response.Content);
});
// async with deserialization
var asyncHandle = client.ExecuteAsync<Person>(request, response => {
Console.WriteLine(response.Data.Name);
});
// abort the request on demand
asyncHandle.Abort();
You can search "C# REST client" on google and judge by yourself. But IMHO, the easier and nicer to code REST client I´ve ever used is Refit.
Why? you define API calls and responses with just an interface. No coding required at all! Even more, all your API calls will be async by default, something needed for mobile apps to be responsive. From the author´s readme:
public interface IGitHubApi
{
[Get("/users/{user}")]
Task<User> GetUser(string user);
}
var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");
var octocat = await gitHubApi.GetUser("octocat");
I´ve used this library on Xamarin Android/iOS projects and it works well. No issues at all.
Hope it helps

Upload an image from iphone to GAE blobstore

I spent all this morning looking for a clear example on how to upload a picture taken with an iPhone to the blobstore, but without succeed.
Currently I have my iPhone app developed, which can send pics to the server in PHP, with this code in the server:
// Function to upload a photo in a file and save data in the DB
function upload($photoData, $descr, $phone) {
// Folder to upload data
$path = $_SERVER['DOCUMENT_ROOT']."/program/data/";
// Check if there was no error during the file upload
if ($photoData['error'] == 0) {
$result = query("INSERT INTO pics(descr, phone) VALUES('%s','%s')", $descr, $phone);
if (!$result['error']) {
// Inserted in the database, go on with file storage
// Obtain database link (in lib.php)
global $link;
// Get the last automatically generated ID
$idPhoto = mysqli_insert_id($link);
// Move the temporarily stored file to a convenient location
if (move_uploaded_file($photoData['tmp_name'], $path.$idPhoto.".jpg")) {
// File moved, all good, generate thumbnail
thumb($path.$idPhoto.".jpg", 180);
print json_encode(array('successful' => 1));
} else {
errorJson('Upload on server problem');
}
} else {
errorJson('Save database problem: '.$result['error']);
}
} else {
errorJson('Upload malfunction.');
}
}
The part in Objective-C that makes this works is (I'm using AFNetworking and the object API sharedInstance is an AFJSONRequestOperation class):
// Upload the image and the description to the web service
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"upload", #"command",
UIImageJPEGRepresentation(originalPhoto, 70), #"file",
description, #"descr",
phoneNumber, #"phone",
nil]
onCompletion:^(NSDictionary *json) {
// Finished and response from server
if (![json objectForKey:#"error"]) {
// Success
[[[UIAlertView alloc]initWithTitle:#"Info"
message:#"Thanks"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles: nil] show];
// Send a notification so the main view can reload the data
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateStream" object:nil];
} else {
// Error
NSString* errorMsg = [json objectForKey:#"error"];
[UIAlertView error:errorMsg];
}
}];
This works fine and the images are saved on the server. But I want to make the same with datastore, which you can't save files. So I made a webpage to practice on save images, and I can upload images without any problem in the blobstore from an standard web form. This is the code I'm using to save it in GAE (forget about my own helper classes or functions like PicturePageHandler or render_page):
# Get and post for the create page
class Create(PicturePageHandler, blobstore_handlers.BlobstoreUploadHandler):
def get(self):
if self.user_logged_in():
# The session for upload a file must be new every reload page
uploadUrl = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", form_action=uploadUrl)
def post(self):
if self.user_logged_in():
# Create a dictionary with the values, we will need in case of error
templateValues = self.template_from_request()
# Test if all data form is valid
testErrors = check_fields(self)
if testErrors[0]:
# No errors, save the object
try:
# Get the file and upload it
uploadFiles = self.get_uploads('picture')
# Get the key returned from blobstore, for the first element
blobInfo = uploadFiles[0]
# Add the key and the permanent url to the template
templateValues['blobKey'] = blobInfo.key()
templateValues['servingUrl'] = images.get_serving_url(blobInfo.key(), size=None)
# Save all
pic = Picture.save(self.user.key, **templateValues)
if pic is None:
logging.error('Picture save error.')
self.redirect("/myPics")
except:
self.render_page("customMessage.htm", custom_msg=_("Problems while uploading the picture."))
else:
# Errors, render the page again, with the values, and showing the errors
templateValues = custom.prepare_errors(templateValues, testErrors[1])
# The session for upload a file must be new every reload page
templateValues['form_action'] = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", **templateValues)
My questions are:
Can I still using my Objective-C JSON call to upload a picture to the server or must I completely change the way to upload the picture?
How can I change the Python server code to get the picture from the JSON, if it is possible?
It's not exactly what you're after, but this might help:
http://brunofuster.wordpress.com/2011/03/11/uploading-an-image-from-iphone-to-appengine-blobstore-using-vraptor/

Categories

Resources