I have been trying to get my frontend to work with a fastAPI to upload a file to a database. I keep hitting the CORS issue, have gone through multiple stackoverflow threads but Im still not any closer to a solution.
Here is my fastAPI code:
from fastapi import (
APIRouter,
Depends,
HTTPException,
UploadFile,
File
)
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import httpx
app = FastAPI()
# Add CORS middleware to the app (not to the router)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)
router = APIRouter(
prefix="/api",
tags=["api"],
responses={404: {"description": "404 Page Not Found"}},
)
@router.get("/")
async def read_items():
return "<h1>Page</h1>"
@router.post("/upload")
async def upload(file: UploadFile = File(...)):
print("Upload")
app.include_router(router)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=20000)
Here is the code for the fastAPI pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: api:latest
imagePullPolicy: Never
ports:
- containerPort: 12980
name: web
Here is the api-service:
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- name: http
protocol: TCP
port: 20000
targetPort: 20000
The nginx proxy default.conf (I am not yet proxying the calls because I want to see if the preflight check passes first):
server {
listen 80;
server_name api.localhost;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
}
proxy_redirect off;
proxy_set_header host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
# proxy_pass http://cos-service.default.svc.cluster.local:20000/;
}
}
I build this nginx conf into a docker image called nginx-cors.
And this is the deployment file for nginx:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-cors
labels:
app: nginx-cors
spec:
replicas: 1
selector:
matchLabels:
app: nginx-cors
template:
metadata:
labels:
app: nginx-cors
spec:
containers:
- name: nginx-cors
image: nginx-cors:latest
imagePullPolicy: Never
ports:
- containerPort: 80
name: nginx
with its own service:
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx-cors
ports:
- name: http
protocol: TCP
port: 11999
targetPort: 80
And finally, the React code for accessing this:
import React, { useState, ChangeEvent, FormEvent } from 'react';
import axios from 'axios';
const FileUpload: React.FC = () => {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [uploadProgress, setUploadProgress] = useState<number>(0);
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files.length > 0) {
setSelectedFile(event.target.files[0]);
}
};
const handleUpload = async (event: FormEvent) => {
event.preventDefault();
if (!selectedFile) {
alert('Please select a file first');
return;
}
const formData = new FormData();
formData.append('file', selectedFile);
console.log("formdata ", formData);
try {
const response = await axios.post('http://nginx-svc:11999/', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
setUploadProgress(percentCompleted);
},
});
if (response.status === 201) {
alert('File uploaded successfully');
} else {
alert('File upload failed');
}
} catch (error) {
console.error('Error uploading file:', error);
alert('Error uploading file');
}
};
return (
<div>
<form onSubmit={handleUpload}>
<input type="file" onChange={handleFileChange} />
<button type="submit">Upload File</button>
</form>
{uploadProgress > 0 && <p>Upload Progress: {uploadProgress}%</p>}
</div>
);
};
export default FileUpload;
When I click the upload button in the browser, it fails with:
and the network debug on my firefox-esr shows the following:
and
Could someone please tell me what’s going wrong?