upload filesusing azure blob storage sdk

167 Views Asked by At

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
1

There are 1 best solutions below

0
On BEST ANSWER

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: enter image description here

Portal: enter image description here

Here is my GitHub link of the entire project to upload a sample image file to Azure blob storage using next.js.