I'm extremely new to React and Python and just trying to do a simple post from a react form to my Python API that will interface with a mongoDB.
I have a form in react that invokes a handleSubmit function on submit. I want the handleSubmit function to POST to my Python API running on port 5000. My react app is running on port 8080.
The handleSubmit looks like this:
handleSubmit(event) {
const axios = require('axios');
const baseUrl = 'http://localhost:5000'
axios.post('http://localhost:5000/api/create', JSON.stringify(params))
.end((error, response) => {
if (!error && response) {
console.log('got a valid response from the server')
} else {
console.log(`Error fetching data from the server: `, error)
}
});
event.preventDefault();
}
Python endpoint code:
#app.route('/api/create', methods=['POST'])
def create(self):
if request.method == 'POST':
print(request.args.get('exp_title'))
return True
return False
When I click the button, my python API endpoint isn't reached because react is trying to post to a route on port 8080. What am I missing?
I've tried using a regular ajax call and get the same result. At one point, I did something and got a CORS error in the browser, but I can't remember how I did that.
To enable cors, you need to install pip install -U flask-cors,
here is the website: https://flask-cors.readthedocs.io/en/latest/
or you can define cors in proxy in your reactjs package.json like here:
https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development
Once you install cors in your python app, try this:
Python app:
#app.route('/api/', methods=['POST', 'GET'])
def api_post():
if request.method == 'POST':
print('post app')
req = request.json
print(req)
return jsonify(name='john')
React app:
function App() {
const [todos, setTodos] = useState(null);
const [value, setValue] = useState('');
function handleSubmit(e) {
e.preventDefault();
const data = { name: value };
console.log('submit');
console.log(value);
fetch('http://127.0.0.1:5000/api/', {
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify(data),
})
.then(res => res.json())
.then(res => console.log(res));
}
function handleValue(e) {
setValue(e.target.value);
}
return (
<section id="app">
<form action="" onSubmit={handleSubmit}>
<input type="text" onChange={handleValue} />
<button> submit </button>
</form>
</section>
);
}
render(<App />, document.querySelector('#root'));
Related
I have a Cloud Function(Python - Flask) that is expecting to receive a form-data with two files, it works well when I request it directly, but using Cloud Task it's not reaching in there. Here is what I get: ImmutableMultiDict([])
ps: Using Python for the Cloud Function and Node.JS for the Cloud Task.
Tried to Google, and searched over here and have no answers, even the docs don't say anything about it. Any tips?
that's the code that I'm using to call Cloud Task:
const auth = new GoogleAuth({})
const client = new CloudTasksClient({ credentials: credentials });
const formData = new FormData();
formData.append('pdf_file', 'x');
const task = {
httpRequest: {
httpMethod: 'POST',
url,
body: formData,
headers: {
"Content-Type": "multipart/form-data"
},
oidcToken: {
serviceAccountEmail: "x#appspot.gserviceaccount.com"
}
}
}
const request = { parent: parent, task: task, auth: auth }
const [ response ] = await client.createTask(request);
console.log(response);
console.log(`created task ${response.name}`);
that's the code for my Cloud Function, that I'm using as a test:
import functions_framework
#functions_framework.http
def main(request):
if request.method != 'POST':
print('ERROR: its not a post request')
return {'error': 'Invalid method'}, 400
print(request.form)
return 'ok'
Frontend = React, backend = FastApi.
How can I simply send an image from the frontend, and have the backend saving it to the local disk ?
I've tried different ways: in an object, in a base64 string, etc.
But I can't manage to deserialize the image in FastApi.
It looks like an encoded string, I tried writing it to a file, or decoding it, but with no success.
const [selectedFile, setSelectedFile] = useState(null);
const changeHandler = (event) => {setSelectedFile(event.target.files[0]); };
const handleSubmit = event => {
const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' },
body: formData2 // Also tried selectedFile
};
fetch('http://0.0.0.0:8000/task/upload_image/'+user_id, requestOptions)
.then(response => response.json())
}
return ( <div
<form onSubmit={handleSubmit}>
<fieldset>
<label htmlFor="image">upload picture</label><br/>
<input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
</fieldset>
<br/>
<Button color="primary" type="submit">Save</Button>
</form>
</div>
);
And the backend:
#router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, request: Request):
body = await request.body()
# fails (TypeError)
with open('/home/backend/test.png', 'wb') as fout:
fout.writelines(body)
I also tried to simply mimic the client with something like this:
curl -F media=#/home/original.png http://0.0.0.0:8000/task/upload_image/3
but same result...
----- [Solved] Removing user_id for simplicity.
The server part must look like this:
#router.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
out_path = 'example/path/file'
async with aiofiles.open(out_path, 'wb') as out_file:
content = await file.read()
await out_file.write(content)
And for some reason, the client part should not include the content-type in the headers:
function TestIt ( ) {
const [selectedFile, setSelectedFile] = useState(null);
const [isFilePicked, setIsFilePicked] = useState(false);
const changeHandler = (event) => {
setSelectedFile(event.target.files[0]);
setIsFilePicked(true);
};
const handleSubmit = event => {
event.preventDefault();
const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);
const requestOptions = {
method: 'POST',
//headers: { 'Content-Type': 'multipart/form-data' }, // DO NOT INCLUDE HEADERS
body: formData2
};
fetch('http://0.0.0.0:8000/task/uploadfile/', requestOptions)
.then(response => response.json())
.then(function (response) {
console.log('response')
console.log(response)
});
}
return ( <div>
<form onSubmit={handleSubmit}>
<fieldset>
<input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
</fieldset>
<Button type="submit">Save</Button>
</form>
</div>
);
}
Replying from to your comment: yes there is a simple snippet example of JS-Fastapi and it was answered by me not long ago.
The reason you are not able to access the file is fairly simple: the naming of the python parameters must match the keys of the formData object.
Instead, you are accessing the raw request, which does not make sense.
Simply change your python code as follows:
from fastapi import UploadFile, File
#router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, file: UploadFile = File(...)):
# Your code goes here
which is well detailed in the official docs
https://fastapi.tiangolo.com/tutorial/request-files/?h=file
FYI
The following are the references to my answers (actually checking, I answered multiple questions related to this topic and should be enough to understand the basic problems one may fall into when uploading files)
How to send a file (docx, doc, pdf or json) to fastapi and predict on it without UI (i.e., HTML)?
How can I upload multiple files using JavaScript and FastAPI?
How to upload file using fastapi with vue? I got error unprocessable 422
Uploading an excel file to FastAPI from a React app
I just learn flask to use with jquery, just want to print out what i typed in , but it print nothing
here is html code
<body>
<input id="name-input" type="text" />
<button id="name-button">Submit Name</button>
<p id="greeting"></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#name-button").click(function (event) {
let message = {
name: $("#name-input").val()
}
$.post("http://10.0.0.4:5000/hello", JSON.stringify(message), function (response) {
$("#greeting").text(response.greeting);
console.log(response);
});
});
</script>
</body>
here is flask code:
from flask import request
from flask import jsonify
from flask import Flask
app = Flask(__name__)
#app.route('/hello',methods=['POST'])
def hello():
message = request.get_json(force=True)
name = message['name']
response = {
'greeting': 'Hello, ' + name + '!'
}
return jsonify(response)
when i click button, it print nothing!. please help, thank a lot
Two issues:
You're using the IP address shown in the example, which is very unlikely to point to your own PC on a network. More likely is 127.0.0.1:5000/hello, which would be localhost if you're running through the dev server. You can actually run the server across the network by providing the --host=0.0.0.0 flag to flask run. NOTE: This is only for the development server; you'll want to look at deployment options when you run this for real
Your route only accepts POST requests, but you're sending a GET request
The HTMl:
<body>
<input id="name-input" type="text" />
<button id="name-button">Submit Name</button>
<p id="greeting"></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#name-button").click(function (event) {
let message = {
name: $("#name-input").val()
}
$.post("http://127.0.0.1:5000/hello", JSON.stringify(message), function (response) {
$("#greeting").text(response.greeting);
console.log(response);
});
});
</script>
</body>
The route:
#app.route('/hello',methods=['GET', 'POST'])
def hello():
message = request.get_json(force=True)
name = message['name']
response = {
'greeting': 'Hello, ' + name + '!'
}
return jsonify(response)
Trying to get json data to front end and have tried a bunch of versions of axios requests but keep getting 404 status code.
This is an example of the front end format:
class App extends Component {
constructor () {
super();
this.state = {
message: ''
};
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
axios.get('./hello')
.then(response => {
this.setState({ message: response.data.text });
})
.catch(error => {
console.log(error);
});
}
render () {
return (
<div className="button-container">
<button className='button' onClick={this.handleClick}>Click Me</button>
<p>{this.state.message}</p>
</div>
)
}
}
and back end routing:
#app.route('/hello')
def hello_world():
return jsonify(text='hello world')
Error message says 'Failed to load resource: the server responded with a status of 404 (Not Found)' or says http://localhost:5003/hello doesn't exist
First check your server, which url and port, your api is exposed
You need to pass complete url to axios constructor otherwise it will send request to same origin/url where your client is hosted, .e.g webapp at localhost:3000.
So your code will be
const SERVER_URL = 'http:localhost:5000'
axios.get(`${SERVER_URL}/hello`)
I'm writing an hybrid web app using flask. By hybrid I mean that there is the conventional web server application built with template engine and there is RESTful API for client side application as well. So here is my confusion:
In my current application, user logs in through the web server so that an HTTP session is created, the user then can do stuff. However, in one of the pages, there is a action that is done via AJAX call to the RESTful part of the same application. Normally in this API, the user will have to authenticate itself again. But here the client side code has no way of knowing the user name and password. What's the correct pattern here?
You can authenticate the user client side in ajax call:
For example:
$.ajax({
url: 'http://example.com/api.ashx/v2/users.xml',
beforeSend: addHeaders,
dataType: "text",
processData: false,
success: function(data, status) {
// do stuff here
},
error: function(xhr, status, error) {
// do stuff here
}
});
var addHeaders = function(xhr) {
var restAuthHeader = readCookie("AuthorizationCookie");
if (restAuthHeader != null) {
xhr.setRequestHeader("Rest-Authorization-Code", restAuthHeader);
}
};
var readCookie = function(input) {
var nameEQ = input + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[ i ];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0)
return c.substring(nameEQ.length, c.length);
}
return null;
};
Let's say you have a form with username and password to authenticate.
<form id="login-form">
<input data-key="username" type="text" placeholder="username" />
<input data-key="password" type="password" placeholder="password" />
<button type="submit">Login</button>
</form>
Your endpoint should return a token and a userid.
var $form = $('#login-form');
// post to your login endpoint with username and password
$.post('/login', {
username: $form.find('input[data-key="username"]').val(),
password: $form.find('input[data-key="password"]').val();
}).done(function (response) {
// put the token and userid in the sessionStorage or localStorage
window.sessionStorage.setItem('token', response.data.token);
window.sessionStorage.setItem('userId', response.data.userId);
}).fail(function (e) {
// handle incorrect credentials here.
alert('authentication failed');
});
You should append these to your headers to request data.
function requestEndpoint(endpoint) {
$.ajax({
// other stuff here you probably know
headers: {
'X-Auth-Token': window.sessionStorage.getItem('token'),
'X-User-Id': window.sessionStorage.getItem('userId'),
'Content-Type': 'application/json'
}
});
}
Just scan for these headers at the endpoints in flask