Fetch does not send body in POST request (request.get_json(silent=True) is empty)
Question:
I am having the following custom component in which I am trying to send a HTTP post request to a server. The curl of this command is as follows:
curl --location --request POST 'https://CLOUD-FUNCTION-HTTP-URL'
--header 'Content-Type: application/json'
--header 'Authorization: Bearer foo'
--header 'Accept: application/json'
--data-raw '{
"message": "hello"
}'
When I send the request with Postman, my server does receive the content of the body
.
However, when I send it from my React app, the body is not found (the content is empty).
On the back-end side, I combined the following two tutorials
- https://cloud.google.com/functions/docs/samples/functions-http-cors (replaced GET with POST)
- https://cloud.google.com/functions/docs/samples/functions-http-content (
request.get_json(silent=True)
is empty when sent from React)
What is causing this mismatch?
import * as React from "react";
import { useState } from "react";
import CircularProgress from "@mui/material/CircularProgress";
import { Button, TextField } from "@mui/material";
import { getBearerToken } from "../auth/firebase/AuthProvider";
export default function Wrapper() {
const [prompt, setPrompt] = useState("Do something");
const [data, setData] = useState([]);
const [status, setStatus] = useState(null);
const handleSubmit = (e) => {
e.preventDefault();
setStatus("loading");
getBearerToken().then(
function (token) {success(token);},
function (error) {setStatus("error");}
);
function success(token) {
const requestOptions = {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify({
"message": "hello"
}),
}
fetch("https://CLOUD-FUNCTION-HTTP-URL", requestOptions)
.then((res) => res.json())
.then((data) => {
console.log(data);
setData(data);
setStatus("success");
})
.catch((err) => {
console.log(err)
console.log(err.message);
setStatus("error");
});
}
};
function handleSetPrompt(e) {
setPrompt(e.target.value);
}
return (
<>
<form onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Standard"
variant="standard"
onChange={handleSetPrompt}
value={prompt}
/>
<Button color="inherit" type="submit">Fetch</Button>
<LoadingSpinner shouldHide={status !== "loading"} />
</form>
<div>
<p>{prompt}</p>
<p>{status}</p>
</div>
</>
);
}
const LoadingSpinner = (props) => (
<div className={props.shouldHide ? "hidden" : undefined}>
<CircularProgress></CircularProgress>
</div>
);
Answers:
The solution to the problem was that I did not had to include the Bearer part, as the method on the back-end that was used to validate did not require a Bearer token but rather an identity token (see link below).
Back-end/Python:
from firebase_admin import auth, initialize_app, get_app
id_token = headers.get("Authorization")
# Verify the ID token while checking if the token is revoked by passing check_revoked=True
decoded_token = auth.verify_id_token(id_token, check_revoked=True)
Front-end/React/JS
export function getIdToken() {
return auth.currentUser.getIdToken(true).then(
function(token) {
return token;
},
function(error) {
console.log(error)
return error;
}
)
}
Related resources:
I am having the following custom component in which I am trying to send a HTTP post request to a server. The curl of this command is as follows:
curl --location --request POST 'https://CLOUD-FUNCTION-HTTP-URL'
--header 'Content-Type: application/json'
--header 'Authorization: Bearer foo'
--header 'Accept: application/json'
--data-raw '{
"message": "hello"
}'
When I send the request with Postman, my server does receive the content of the body
.
However, when I send it from my React app, the body is not found (the content is empty).
On the back-end side, I combined the following two tutorials
- https://cloud.google.com/functions/docs/samples/functions-http-cors (replaced GET with POST)
- https://cloud.google.com/functions/docs/samples/functions-http-content (
request.get_json(silent=True)
is empty when sent from React)
What is causing this mismatch?
import * as React from "react";
import { useState } from "react";
import CircularProgress from "@mui/material/CircularProgress";
import { Button, TextField } from "@mui/material";
import { getBearerToken } from "../auth/firebase/AuthProvider";
export default function Wrapper() {
const [prompt, setPrompt] = useState("Do something");
const [data, setData] = useState([]);
const [status, setStatus] = useState(null);
const handleSubmit = (e) => {
e.preventDefault();
setStatus("loading");
getBearerToken().then(
function (token) {success(token);},
function (error) {setStatus("error");}
);
function success(token) {
const requestOptions = {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer " + token
},
body: JSON.stringify({
"message": "hello"
}),
}
fetch("https://CLOUD-FUNCTION-HTTP-URL", requestOptions)
.then((res) => res.json())
.then((data) => {
console.log(data);
setData(data);
setStatus("success");
})
.catch((err) => {
console.log(err)
console.log(err.message);
setStatus("error");
});
}
};
function handleSetPrompt(e) {
setPrompt(e.target.value);
}
return (
<>
<form onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Standard"
variant="standard"
onChange={handleSetPrompt}
value={prompt}
/>
<Button color="inherit" type="submit">Fetch</Button>
<LoadingSpinner shouldHide={status !== "loading"} />
</form>
<div>
<p>{prompt}</p>
<p>{status}</p>
</div>
</>
);
}
const LoadingSpinner = (props) => (
<div className={props.shouldHide ? "hidden" : undefined}>
<CircularProgress></CircularProgress>
</div>
);
The solution to the problem was that I did not had to include the Bearer part, as the method on the back-end that was used to validate did not require a Bearer token but rather an identity token (see link below).
Back-end/Python:
from firebase_admin import auth, initialize_app, get_app
id_token = headers.get("Authorization")
# Verify the ID token while checking if the token is revoked by passing check_revoked=True
decoded_token = auth.verify_id_token(id_token, check_revoked=True)
Front-end/React/JS
export function getIdToken() {
return auth.currentUser.getIdToken(true).then(
function(token) {
return token;
},
function(error) {
console.log(error)
return error;
}
)
}
Related resources: