pages/api/file.ts:
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { NextApiRequest, NextApiResponse } from "next";
export interface GetFileProps {
url: string;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<GetFileProps>,
) {
const s3client = new S3Client({
region: "region",
credentials: {
accessKeyId: "",
secretAccessKey: "",
},
});
const command = new GetObjectCommand({
Bucket: "bucketName",
Key: req.query.path as string,
});
const url = await getSignedUrl(s3client, command, { expiresIn: 900 });
res.status(200).json({ url });
}
The URL obtained can be utilized by the frontend:
const aRef = React.useRef<any>();
const getFileUrlAndDownload = React.useCallback((path: string) => {
from(fetch(`http://localhost:3000/api/file?path=${path}`))
.pipe(
mergeMap(response => {
return response.json();
}),
mergeMap((res: GetFileProps) => {
aRef.current.href = res.url;
aRef.current.click();
return EMPTY;
}),
catchError(err => {
console.log("Error fetching download URL", err);
return err;
}),
)
.subscribe();
}, []);
This link needs to be rendered in the tsx file:
<a ref={aRef} />
To trigger the download process, an onClick event should call getFileUrlAndDownload with the file path.