I habe a client written in Javascript (react) which runs on localhost:3000 Here I have a button that sends the credentials to my backend written in python and using flask. The endpoint is running on localhost:5000/login.
My frontend code looks like this:
loginToDatabase = async () => {
console.log("login to database. user: " + this.state.user+" pw: "+this.state.password);
const response = await fetch("http://localhost:5000/login",{
method: 'POST',
body: {
"user": this.state.user,
"password": this.state.password
},
headers: {
"Content-Type": "application/json"
}
});
console.log("response: "+response)
};
My backend code looks like this:
@app.route("/login", methods=['POST'])
def login():
jsonRequest = request.get_json()
receivedUser = jsonRequest.get('user')
receivedPassword = jsonRequest.get('password')
isConnected = opendatabase.openDatabase('localhost',receivedUser,receivedPassword)
if(isConnected == True):
body = json.dumps({
"connection":isConnected,
})
jsonResponse = Response(
body,
mimetype="application/json",
headers={
"Access-Control-Allow-Origin" : "*",
}
)
return (jsonResponse)
else:
body = isConnected
jsonResponse = Response(
body,
headers={
"Access-Control-Allow-Origin" : "*",
)
return (jsonResponse, 401)
Testing the API with Postman works as expected. However using the frontend I receive this error:
Access to fetch at 'http://localhost:5000/login' from origin 'http://localhost:3000' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
After doing some research I figured out why this happens and that I need the header
"Access-Control-Allow-Origin" : "*"
which I included. But still could not make it work. I then read here https://developer.mozilla.org/de/docs/Web/HTTP/CORS that does not work with application/json.
The only allowed values for the Content-Type header are: application/x-www-form-urlencoded, multipart/form-data, text/plain
However I also read here Can't send a post request when the 'Content-Type' is set to 'application/json' that I can set a header
->header('Access-Control-Allow-Headers', 'Content-Type');
which I also tried like this:
if(isConnected == True):
body = json.dumps({
"connection":isConnected,
})
jsonResponse = Response(
body,
mimetype="application/json",
headers={
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Headers": "Content-Type",
}
)
return (jsonResponse)
else:
body = isConnected
jsonResponse = Response(
body,
headers={
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Headers": "Content-Type"
}
)
return (jsonResponse, 401)
But that does also not work. There are also many more posts about this topic but so far I could not find a solution. I am also new to APIs and webdevelopment. And also I think my shown login process is far from perfect. It is really just about getting the REST call to work.
Is there a way to solve this and still using JSON? Surely I could use someting like text/plain but that would not be satisfying.
Also (maybe related) if I use text/plain in the frontend I don't receive the error, but in the backend I don't know how the receive the data send via POST. As you can see in the attached picture, I seem to get an empty object?
Where is my mistake and what is the best way to solve this issue with JSON?