I am trying to upload my text/pf files to a container in azure blob storage using Next js 13 as the frontend, I am able to upload the file but the name for the uploaded blob does not match the selected file and when a new file is uploaded the content in te blob is overwritten because the name of the blob is same.
I want to get the name of the uploaded file as the blob name.
My Component Code for Next js 13 :
"use client";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useToast } from "@/components/ui/use-toast";
import { DialogClose } from "@radix-ui/react-dialog";
import { useState } from "react";
export default function UploadData() {
const [file, setFile] = useState<string | null>(null);
const { toast } = useToast();
// hande selected file by the user
const handleSelectFile = (event: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = event.target.files?.[0];
if (selectedFile) {
const reader = new FileReader();
reader.readAsDataURL(selectedFile)
reader.onload = () => {
setFile(reader.result as string)
}
reader.onerror = () => {
console.log('reader.error', reader.error);
};
}
};
// handles File submitted by the user
const handleSubmit = async () => {
try {
const headers = {
'Content-Type': 'application/octet-stream',
};
const response = await fetch('/api/ingest', {
method: 'POST',
body: file,
headers: headers,
});
console.log(response.body)
toast({
title: "Data uploaded successfully",
})
} catch (error: any) {
toast({
variant: "destructive",
title: "Data uploaded successfully",
description: error
})
}
}
return (
<>
<Dialog>
<DialogTrigger asChild>
<Button>Upload</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Select file
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name">URL</Label>
<Input
id="name"
type="file"
onChange={handleSelectFile}
className="col-span-full"
/>
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button
type="submit"
onClick={handleSubmit}
>
Submit
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}
My POST API for uploading file to azure blob storage :
//Conect to azure storage account
const blobService = new BlobServiceClient(
`https://${process.env.AZURE_STORAGE_ACCOUNT}.blob.core.windows.net/?${process.env.AZURE_STORAGE_SAS_TOKEN}`
);
//Connect to azure blob storage container
const containerClient = blobService.getContainerClient(
process.env.AZURE_BLOB_STORAGE_CONTAINER
);
export async function POST(request: Request, res: Response) {
const blobClient = containerClient.getBlockBlobClient(request.blob.name);
console.log("blob client", request.blob.name);
try {
const buffer = await getStreamAsArrayBuffer(request.body);
console.log("Buffer", buffer);
await blobClient.uploadData(buffer, {
blobHTTPHeaders: {
blobContentType: request.headers.get("Content-Type") || "",
},
});
return NextResponse.json(res);
} catch (e) {
console.log(e);
return NextResponse.error();
}
}
Any help is appreciated
Setting Blob Name Matching Original File Name
You should pass the original file name to the API, which can then be used to set the blob name. One way to achieve this is by including the file name in your API request.
const handleSubmit = async () => {
try {
const headers = {
'Content-Type': 'application/octet-stream',
'X-File-Name': file?.name // Pass the file name as a header
};
const response = await fetch('/api/ingest', {
method: 'POST',
body: file,
headers: headers,
});
} catch (error: any) {
}
}
On the API side, you can then get the filename from the headers:
export async function POST(request: Request, res: Response) {
const blobName = request.headers.get("X-File-Name") || "defaultBlobName"; // Use a default name if header not provided
const blobClient = containerClient.getBlockBlobClient(blobName);
}
Prevent Overwriting
You can append a timestamp or UUID to the filename.
const blobName = (request.headers.get("X-File-Name") || "defaultBlobName") + "-" + Date.now();