I am trying to upload files from Next js 13 application to azure blob storage
I think my file is an object and it expects a blob or buffer, I tried doing that but not of much help either.
my component code
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
"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";
import { ButtonLoading } from "../LoadingButton";
import axios from 'axios';
export default function UploadData() {
const [file, setFile] = useState<File | null>(null);
const [isLoading, setIsLoading] = useState(false);
const { toast } = useToast();
const handleUrlInput = (event: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = event.target.files?.[0]
if (selectedFile) {
setFile(selectedFile);
}
};
const handleSubmit = async () => {
const formData = new FormData();
if (file) {
formData.append('file', file);
}
console.log(formData)
const response = axios.post('/api/ingest', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
// Handle the response
if ((await response).status === 200) {
// File uploaded successfully
console.log('File uploaded successfully!');
} else {
// Something went wrong
console.log('Error uploading file:', response);
}
}
return (
<Dialog>
<DialogTrigger asChild>
{isLoading ? <ButtonLoading /> : <Button>Upload</Button>}
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Enter URL which you want to provide as input for retrieving
information.
</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={handleUrlInput}
className="col-span-full"
/>
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button
type="submit"
onClick={handleSubmit}
>
Submit
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
My API code
export async function POST(request: Request, res: Response) {
try {
// const file = (await request.formData())?.get("file") as Blob;
const formData = await request.formData();
const filePart = formData.get("file");
console.log("filePart", typeof filePart);
if (filePart instanceof Blob) {
const fileName = filePart.name;
const buffer = Buffer.from(await filePart.arrayBuffer());
console.log("File Name:", fileName);
console.log("Buffer:", buffer);
const blobClient = containerClient.getBlockBlobClient(fileName);
await blobClient.uploadData(buffer);
return NextResponse.json(res);
} else {
console.log("Invalid file format");
return NextResponse.error();
}
} catch (e) {
console.log(e);
return NextResponse.error();
}
}
I am not able to upload files, the error displayed is Invalid file format:
⨯ RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: 0
I am not able to upload files, the error displayed is:
Invalid file format ⨯ RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: 0
According to this SO-thread by Gaurav Mantri, Azure blob storage doesn't support the multipart/form-data
content type.
To upload multiple files you can use application/octet-stream
or if you need to upload an image you can use the content-type= image/jpeg
Here is a sample code that I tried to upload images to Azure blob storage using the next.js app.
Code:
azconnect.js
import { BlobServiceClient } from '@azure/storage-blob';
const connectionString = process.env.AZURE_CONNECTION;
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString);
const containerName = process.env.AZURE_CONTAINER_NAME;
async function uploadImageToAzureStorage(fileBuffer, fileName, contentType) {
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
try {
await blockBlobClient.uploadData(
fileBuffer,
{
blobHTTPHeaders: { blobContentType: contentType },
}
);
return blockBlobClient.url;
} catch (error) {
console.error('Error uploading image:', error);
throw error;
}
}
export { uploadImageToAzureStorage }
Components:
import { useState } from 'react';
const ImageUploadForm = () => {
const [image, setImage] = useState(null);
const handleSubmit = (e) => {
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onload = () => {
setImage(reader.result);
};
reader.onerror = () => {
console.log('reader.error', reader.error);
};
};
const uploadImage = async () => {
try {
const headers = {
'Content-Type': 'image/jpeg',
};
const response = await fetch('/api/postImage', {
method: 'POST',
body: image,
headers: headers,
});
if (response.ok) {
console.log('Image uploaded successfully!');
} else {
console.error('Image upload failed.');
}
} catch (error) {
console.error('Error uploading image:', error);
}
};
return (
<>
<input type="file" accept="image/*" onChange={handleSubmit} />
<button onClick={uploadImage}>Upload Image</button>
</>
);
};
export default ImageUploadForm;
Browser:
Portal:
Here is my GitHub link of the entire project to upload a sample image file to Azure blob storage using next.js.