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
Related
I am using Fast API server and exposed the api. And from my JS using axios i am maing call to this server.
And I am using interceptor to check the token in headers.
I also have added CORSMiddleware
Here is the code
origins = ["*", "http://localhost:3002"]
# Creating FastAPI Application
app = FastAPI()
app.include_router(chat_service.router)
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)
and the interceptor
#app.middleware("http")
async def verifyJWT(request: Request, call_next):
try:
token = request.headers['token']
...
except:
return JSONResponse(content={
"err": "You are not authorized"
}, status_code=401)
And here is the code from JS using axios
$.ajax({
url: url,
type: "POST",
crossDomain: true,
contentType: "application/json",
headers: {
"accept": "*/*",
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json" ,
"token": TOKEN
},
data: my_data,
success: function (botResponse, status) {
...
},
error: function (xhr, textStatus, errorThrown) {
.. .
}
});
I am passing the token in headers
but on Fast api server it throws the error as there is no token in the headers
and on the console it shows
Access to XMLHttpRequest at 'http://localhost:8082/api/process' from origin 'http://localhost:3002' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
and if i make the call from ThunderClient it works.
what can be the issue and how can i solve this?
The problem is in your origins = ["*", "http://localhost:3002"]. As far as I understand, when you have set allow_credentials=True in your Middleware, you cannot use the wildcard (i.e. "*") for allow_origins.
Here is an excerpt from the docs.
allow_credentials - Indicate that cookies should be supported for cross-origin requests. Defaults to False. Also, allow_origins cannot be set to ['*'] for credentials to be allowed, origins must be specified.
Link to docs here: https://fastapi.tiangolo.com/tutorial/cors/
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
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.
I'm implementing a vegetable retail price predicting web application for one of my university projects using Flask and ReactJs. My POST requests work fine on Postman, but when I try to use a form in ReactJs to make a POST request, I get the following error:
Access to fetch at 'http://127.0.0.1:5000/vegetable' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
api_calls.js:7 POST http://127.0.0.1:5000/vegetable net::ERR_FAILED
Uncaught (in promise) TypeError: Cannot read property 'predicted_retail_price' of undefined
at Pricing.jsx:102
TypeError: Failed to fetch api_calls.js:22
API Results:::: undefined Pricing.jsx:101
But I have added following code segment in my server.py:
from flask import Flask, jsonify
from routes.lstm_price_route import lstm_price_blueprint
from routes.lstm_route import lstm_blueprint
from flask_cors import CORS, cross_origin
import csv
import json
server = Flask(__name__)
CORS(server)
server.config.from_object('config')
server.config['JSON_AS_ASCII'] = False
server.config['CORS_HEADERS'] = 'Content-Type'
server.register_blueprint(lstm_blueprint)
server.register_blueprint(lstm_price_blueprint)
The method in my Flask app(lstm_price_model.py):
def get_tomato_prediction(self, centre_name, date):
Data = pd.read_csv('lstm_price_prediction_tomato.csv')
result = {
'predicted_retail_price': Data.loc[(Data['centre_name'] == centre_name) & (Data['date'] == date), 'predicted_retail_price'].values[0]}
return jsonify(result)
The fetch call in React.js app(api_calls.js):
export const getPredictedPrice = async (centreName, pDate, vegetable) => {
try {
let price_prediction = await fetch(
`${BASE_URL}/vegetable`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
centre: centreName,
date: pDate,
commodity: vegetable
})
}
);
let result = await price_prediction.json();
return result;
} catch (error) {
console.log(error);
}
};
Github link for the frontend code - https://github.com/HashiniW/CDAP-F
Github link for the backend code - https://github.com/HashiniW/CDAP-B
Any suggestions to overcome this error? Thank You!
Try using mode: "no-cors" on the fetch frontend.
export const getPredictedPrice = async (centreName, pDate, vegetable) => {
try {
let price_prediction = await fetch(
`${BASE_URL}/vegetable`,
{
//Adding mode: no-cors may work
mode: "no-cors",
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
centre: centreName,
date: pDate,
commodity: vegetable
})
}
);
let result = await price_prediction.json();
return result;
} catch (error) {
console.log(error);
}
};
Use following code in your python project :
from flask import Flask, jsonify
from routes.lstm_price_route import lstm_price_blueprint
from routes.lstm_route import lstm_blueprint
from flask_cors import CORS, cross_origin
import csv
import json
server = Flask(__name__)
cors = CORS(server , resources={r"/*": {"origins": "*", "allow_headers": "*", "expose_headers": "*"}})
server.register_blueprint(lstm_blueprint)
server.register_blueprint(lstm_price_blueprint)
here is the line of code returning the error message from flask api
return jsonify(message='wrong username or password'),400
reading it from here in react js
axios
.post("http://127.0.0.1:5000/authentication/login", body)
.then((res) => {
console.log(res)
})
.catch((error) => {
console.log(error);
});
and this is what i see in the console
{"message":"Request failed with status code 400","name":"Error","stack":"Error: Request failed with status code 400\n at createError (http://localhost:3000/static/js/1.chunk.js:854:15)\n at settle (http://localhost:3000/static/js/1.chunk.js:1075:12)\n at XMLHttpRequest.handleLoad (http://localhost:3000/static/js/1.chunk.js:329:7)","config":{"url":"http://127.0.0.1:5000/auth/login","method":"post","data":"{\"phone\":\"\",\"password\":\"\"}","headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1}}
The results doesn't not contain the custom message 'wrong username or password'
have actually gotten the solution, something simple
the error data can be accessed from
console.log(error.response.data);
flask by default returns html page instead of json when error is thrown. to make run return normal json as with 200's responses write this in your flask app:
from werkzeug.exceptions import HTTPException
#app.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
print(e)
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
response.content_type = "application/json"
return response
then for example for such return in flask
...
return json.dumps(str(e)), 409
and then you can catch in your js:
...
}).then(function(response) {
...
}).catch((error) => {
console.log(error.response.data); // will log your error as string
})