Hi there I am doing a project with a React Frontend and Flask Backend. I am using axios to make calls from the Frontend to the Backend, but I am having trouble accessing the data I am sending with my request. I have tried several different methods of accessing the data but have no luck printing my variables.
Here is my flask endpoint:
#app.route('/login')
#cross_origin()
def login():
print(request.data)
return "Hello World"
Here is my axios call:
let options = {
method: 'GET',
url: flaskEndpoint+ "/login",
data: JSON.stringify(loginData),
// crossOrigin:'Access-Control-Allow-Origin',
crossOrigin:'*',
headers: {
'Content-Type': 'application/json'
},
json: true
}
console.log(JSON.stringify(loginData))
axios(options)
.then(response => {
console.log(response);
// this.setState({
//
// })
setAuth(true);
Cookies.set("user", "loginTrue");
})
.catch(error => {
console.log("Error in the axios call:" + error);
})
}
And here is the result in the flask terminal:
What am I doing wrong and is there a better way?
So I should have used "print(request.json)" instead. Then I could access the data being sent, or use "request.json.get('username')" to get a particular value.
Related
I am unable to track down this issue I am having attempting to send a FormData object (containing a file) to a Flask-RESTful application. On the ReactJS side i have the following code:
const updateAvatar = ({ target }) => {
if (target.value) {
let form = new FormData()
form.append("file", target.files[0])
fetch(`myurl/avatar`, {
credentials: "include",
method: "POST",
headers: { 'Content-Type':"application/x-www-form-urlencoded" },
body: form
})
.then(response => response.json())
.then(data => Do Something)
}
}
On the Flask side I have the following code:
def post(self,user):
if request.endpoint=="avatar":
print('I can see this message but I error out on the next line')
f=request.files["file"]
The f=request.files["file"] causes the server to return a 400 error. I thought this was straight forward but i'm a bit stuck here.
One other thing to mention: I am running in a local HTTPS environment using credentials.
Any help would be much appreciated.
I've setup my project, i.e. I have created a front-end in React, and a back-end in Flask.
In my front-end I call my back-end with a post method with the following code:
function POST(path, data) {
return fetch(`${fetchUrl}${path}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + RequestAccessToken(),
},
body: JSON.stringify(data)
}
)
}
Where RequestTokenAccess():
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const name = accounts[0] && accounts[0].name;
function RequestAccessToken() {
const request = {
...loginRequest,
account: accounts[0]
};
instance.acquireTokenSilent(request).then((response) => {
setAccessToken(response.accessToken);
}).catch((e) => {
instance.acquireTokenPopup(request).then((response) => {
setAccessToken(response.accessToken);
});
});
}
And then just the following to actually make the call to the back-end:
const [data, setData] = useState()
function fetchData(e) {
e?.preventDefault();
POST('/my_app', { data: data }).then(
async (response) => {
const json = await response.json()
setData(json.return_data)
}
)
}
So for the front-end everything is working. I can get a MS Login that authorizes me so I can actually se the front-end, and I can also get a token from the RequestAccessToken function, which is given as a header to the back-end call. So everything seems to be set on the front-end part. However, the back-end calls also need to be secure is my guess, but I am not sure how that works.
Basically my app.py file looks something like:
from flask import Flask, request, jsonify
from my_app_func import MyAppFunc
app = Flask(__name__)
#app.post("/api/my_app")
def my_app():
data = request.json.get("data")
return_data = MyAppFunction(data)
return return_data
So basically, what do I need in order secure back-end calls ? I have the token as a Bearer Token in the post call. But what is the next step ? What do I actually do with it ?
I also have the same question, but couldn't find answer. Below is what works for me:
If you want to validate the user from flask, you can send the token along with your request from react.
Then within flask, validate the user by making a request to microsoft graph api.
Here is one example how to do this:
https://github.com/Azure-Samples/ms-identity-python-flask-webapp-call-graph
Another question for you is why you can directly concatenate RequestAccessToken() as a string? isn't it only call the setAccessToken? I ask because in my react app, I don't know how to export the token so that other function can use it. I ended up using the MSAL.js v2, not the one for react.
You have to register another app on the portal azure and and give permissions to the api and configure that in the another app in portal azure . Try to do something in that space.
I am trying to send a post request from react to flask using the following code:
function App() {
const [currentTime, setCurrentTime] = useState(0);
const [accessToken, setAccessToken] = useState(null);
const clicked = 'clicked';
useEffect(() => {
fetch('/time').then(res => res.json()).then(data => {
setCurrentTime(data.time);
});
}, []);
useEffect(() => {
// POST request using fetch inside useEffect React hook
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React Hooks POST Request Example',action: 'clicked' })
};
var myParams = {
data: requestOptions
}
fetch('http://127.0.0.1:5000/login', myParams)
.then(response => response.json())
.then(data => setAccessToken(data.access_token));
// empty dependency array means this effect will only run once (like componentDidMount in classes)
}, []);
return (
<div className="App">
<div className="leftPane">
<div className="joyStick" >
<Joystick size={300} baseColor="gray" stickColor="black" ></Joystick>
</div>
<p>The current time is {currentTime}.</p>
<p>The access token is {accessToken}.</p>
</div>
And the flask code is
from __future__ import print_function
from flask import Flask, jsonify, request
from flask_cors import CORS
import time
from flask import Flask
import sys
robotIP="10.7.4.109"
PORT=9559
app = Flask(__name__)
access_token='a'
action="d"
#app.route('/time')
def get_current_time():
return {'time': time.time()}
#app.route('/login', methods=['POST'])
def nao():
nao_json = request.get_json()
if not nao_json:
return jsonify({'msg': 'Missing JSON'}), 400
action = nao_json.get('action')
access_token= action+'s'
print(access_token, file=sys.stderr)
return jsonify({'access_token': access_token}), 200
But every time I run both them both, I get the 'msg': 'Missing JSON' message I have defined and the data from react is never available in flask,even though the get request works.I am not sure what I am doing wrong here.
The problem actually is that this is a cross origin request which must be allowed by the server.
Place this function on your Python code:
#app.after_request
def set_headers(response):
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Headers"] = "*"
response.headers["Access-Control-Allow-Methods"] = "*"
return response
Note:
If react is served from the same server this won't be necessary.
You should set the value of these headers to be as strict as possible on production. The above example is too permissive.
You could serve your React aplication from Flask, thus not requiring these headers to be set. You could use something like this to serve the main react file:
#app.route('/', defaults={'path': ''})
#app.route('/<string:path>')
#app.route('/<path:path>')
def index(path: str):
current_app.logger.debug(path)
return bp_main.send_static_file('path/to/dist/index.html')
Where path/to/dist/index.html would be on the static folder.
See more at:
MDN Web docs
Stackoverflow: How to enable CORS in flask
Stackoverflow: Catch all routes for Flask
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 try to send a base64 json form node.js server to python flask server and than return a same base64 code back to node.js server. Flask can successfully receive my json but when it response to node and node try to print out the response. I got a error message say: "Unexpected end of JSON input". I found the reason is node server can not receive the base64 completely. It just only receive a small portion. What is the problem? Is post request has a string limit?
I tested when I change the base64 code to a short string. Node server can receive response normally.
Anyone can help me? Thank you.
This is my code:
<<< Node.js Server >>>
var express = require('express');
var http = require('http');
var app = express();
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(10000, () => console.log('Running on http://localhost:10000'));
postData = JSON.stringify({
'code': <base64 code or short string here>
});
var options = {
hostname: 'localhost',
port: 10001,
path: '/test',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
var req = http.request(options, (res) => {
res.on('data', (chunk) => {
var data = JSON.parse(chunk);
console.log(data.message);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
req.write(postData);
req.end();
<<< Python Flask Server >>>
from flask import Flask
from flask import request
from flask import jsonify
app = Flask(__name__)
#app.route('/test', methods=['POST'])
def test():
request_data = request.get_json()
print(request_data['code'])
return jsonify(
message = request_data['code']
)
app.run(host='localhost', port=10001)
In NodeJS code, in data event, you will get chunk data(partial data), you need to wait until end event and then parse, following example may help you
var req = http.request(options, (res) => {
var data = '';
res.on('data', (chunk) => {
data += chunk.toString(); // buffer to string
});
res.on('end', () => {
data = JSON.parse(data);
console.log(data.message);
console.log('No more data in response.');
});
});