The following code works perfectly when I hit this API using Swagger UI. However, it fails to perform when it is being hit from a react frontend, showing status code 422 unprocessable entity
. Below is my FastAPI endpoint:
@post.post('/post')
async def create_post(post_text: str, image: bytes = File(None), token: str = Depends(oauth2_scheme), db: Session = Depends(database.get_db)):
user_info = await services.get_user_info(token)
username = user_info["username"]
print(username)
image_url = None
if image:
# Generate a unique filename for the image
image_filename = f"{username}_{uuid.uuid4().hex}.jpg"
# print(image_filename)
# Save the image to bytes and send to MinIO bucket
# image_bytes = await image.read()
image_bytes = base64.b64decode(image.split(",")[1])
minio_client.put_object(
"minilinkedindistributed",
image_filename,
io.BytesIO(image_bytes),
length=len(image_bytes),
content_type="image/jpeg"
)
# Construct the image URL based on MinIO server URL and bucket name
image_url = f"http://127.0.0.1:9000/minilinkedindistributed/{image_filename}"
print(image_url)
elif image is None or image.filename == '':
raise HTTPException(status_code=400, detail='Invalid or empty image file')
# Create the post
new_post = services.make_post(db, username, post_text, image_url)
headers = {"Authorization": f"Bearer {token}"}
# Get all users (except the one who posted)
async with httpx.AsyncClient() as client:
response = await client.get("http://127.0.0.1:8000/api/v1/all_users_except_poster", headers=headers)
if response.status_code == 200:
all_users_except_poster = response.json()
else:
raise HTTPException(status_code=response.status_code, detail="Failed to fetch users from user service")
# Create a notification for each user
for user_to_notify in all_users_except_poster:
notification_data = {
'notification_text': f"{username} made a new post...",
'pid' : new_post.id,
'username' : user_to_notify["username"],
'notification_datetime' : datetime.utcnow().isoformat(),
'is_read' : False
}
async with httpx.AsyncClient() as client:
response = await client.post("http://127.0.0.1:8002/api/v1/notification", json=notification_data, headers=headers)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail="Failed to send notification")
return{"message" : new_post}
and below is my react component:
const HomePage = () => {
const [posts, setPosts] = useState([]);
const [loggedIn, setLoggedIn] = useState(false);
const [postText, setPostText] = useState('');
const [selectedImage, setSelectedImage] = useState(null);
const [notifications, setNotifications] = useState([]);
const navigate = useNavigate();
useEffect(() => {
const access_token = localStorage.getItem('access_token');
if (access_token) {
setLoggedIn(true);
fetchPosts(access_token);
}
}, []);
const handlePostTextChange = (event) => {
setPostText(event.target.value);
};
const handleImageChange = (event) => {
setSelectedImage(event.target.files[0]);
};
const handleSubmitPost = async () => {
const formData = new FormData();
formData.append('post_text', postText); // Make sure 'postText' holds the user's post text
if (selectedImage) {
formData.append('image', selectedImage, selectedImage.name); // Make sure 'selectedImage' holds the user's selected image
}else console.log('Invalid or empty image file');
console.log("Post Text:", postText);
console.log("Selected Image:", selectedImage);
console.log('FormData:', formData);
const access_token = localStorage.getItem('access_token');
// Make a POST request to create a new post
try {
const response = await axios.post(`${API_BASE_URL}/post`, formData, {
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'multipart/form-data', // Set the correct content type for the form data
},
});
// Refresh the posts after successful submission
fetchPosts(access_token);
} catch (error) {
console.error('Error submitting post:', error.response);
}
};
Stuck here, any solution will help. Thank you.
In general, the 422 (unprocessable entity)
response includes an error message about exactly which part/value in your request is missing or doesn't match the expected format. Hence, please have a look at that error message and include it in your question.
In your case, you seem to be using axios
in the frontend to post Form
data to the FastAPI backend. However, the way the post_text
argument is defined in your endpoint is expected as query, not Form
, parameter.
Example of post_text
expected as query parameter
@app.post('/create')
async def create_post(post_text: str):
pass
As described in this answer, as well as here and here (please refer to those posts for more details and examples):
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
Hence, if you would like post_text
to be a Form
parameter, it should instead be declared as follows:
Example of post_text
expected as Form
parameter
from fastapi import Form
@app.post('/create')
async def create_post(post_text: str = Form(...)):
pass
Related answers demonstrating how to post File
/Form
data to FastAPI backend through axios
or fetch
request in the frontend can be found here, here, as well as here, here and here.