I have a react redux application and a django server. My django server has an endpoint where I pull a file from s3 and base64 encode the file and return the encoded string. When my redux fetch action is fulfilled I want to download the file without navigating to a new page in my react app. Here is the code:
// DocumentReducer.tsx (+ all necessary imports)
export const getDocument = createAsyncThunk("document/download", async (payload: any) => {
const {id} = payload
const response = await instance.get(`tables/document/download/${id}`)
return response.data
})
const documentSlice = createSlice({
name: "document",
initialState: initialState,
reducers:{},
extraReducers: (builder) => {
...
builder.addCase(getDocument.fulfilled, (state, action) => {
const file = action.payload.file
window.location.href = 'data:application/octet-stream;base64,' + file
state.status = 'fulfilled'
})
}
})
// ExportComponent.tsx (+ all necessary imports)
export const ExportButton: React.FC<ExportButtonProps> = ({document_id}) => {
const dispatch = useAppDispatch()
const handleClick = () => {
const payload = {id: document_id}
dispatch(getDocument(payload))
}
return (
<Button variant="contained" size="small" onClick={handleClick}>
<div className="flex gap-3">
<p>Export</p>
<ArrowDownTrayIcon className='w-4 text-white'/>
</div>
</Button>
)
}
On the server side:
# views.py
def encode_document(s3_key):
""" get document from s3 and base 64 encode the document """
buffer = BytesIO()
output_stream = BytesIO()
S3_CLIENT.download_fileobj("BUCKET_NAME", s3_key, buffer)
encoded = b64encode(buffer.getvalue()).decode()
return encoded
class DocumentS3(APIView):
parser_classes = [JSONParser]
permission_classes = [IsAuthenticated]
def get(self, request, document_id):
document = Document.objects.get(id=document_id)
encoded = encode_document(document.s3_key)
print(encoded[:10])
return Response({"file": encoded}, status=status.HTTP_200_OK)
My server successfully returns the necessary encoded bytes. The download link takes me to a notfound page. Does anyone know how to make this navigation successful in redux?