1

I am currently working on a project where I need to implement file uploads to Azure Blob Storage. I have already set up the backend using Node.js with Express and the @azure/storage-blob library. However, I'm facing difficulties with the frontend implementation, and I could use some guidance to ensure that both frontend and backend are correctly integrated. Frontend Implementation: I have tried to create a basic frontend using React, but I'm encountering a 400 error when attempting to upload a file to the server. I'm not sure if I'm constructing the fetch() request correctly or if there are any issues with the FormData object. The file selection and form submission seem to be working, but the uploaded file doesn't reach the backend as expected.

Dashboard.jsx file:

import React from 'react';
import { useState } from 'react';

function Dashboard() {
  const [selectedFile, setSelectedFile] = useState(null);

  const handleFileChange = (e) => {
    setSelectedFile(e.target.files[0]);
  };

  const handleFileUpload = async () => {
    try {
      const formData = new FormData();
      console.log(formData);
      formData.append('file', selectedFile);

      const response = await fetch('http://localhost:3000/api/upload', {
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        body: JSON.stringify({
          originalname: formData,
          mimetype: formData,
          size: formData
        }),
      });

      if (response.ok) {
        const data = await response.json();
        console.log(data.message);
        // You can handle success actions here if needed
      } else {
        console.error('File upload failed.');
        // You can handle error actions here if needed
      }
    } catch (error) {
      console.error('Error uploading file:', error);
    }
  };

  return (
    <div>
      <h1>File Upload</h1>
      <input type="file" onChange={handleFileChange} />
      <button onClick={handleFileUpload} disabled={!selectedFile}>
        Upload File
      </button>
    </div>
  );
}

export default Dashboard

Backend Implementation: On the backend, I have set up the necessary routes to handle file uploads. I am using multer to handle the file parsing and storage. The backend code uses the @azure/storage-blob library to interact with Azure Blob Storage. However, since the frontend is not functioning as expected, I'm unable to verify if the backend is working correctly.

uploadController.js file:

const { BlobServiceClient, StorageSharedKeyCredential } = require('@azure/storage-blob');
const { v4: uuidv4 } = require('uuid');
const multer = require('multer');
const File = require('../models/files');

require('dotenv').config();

const sharedKeyCredential = new StorageSharedKeyCredential(
    process.env.AZURE_STORAGE_ACCOUNT_NAME,
    process.env.AZURE_STORAGE_ACCOUNT_KEY
);

const blobServiceClient = new BlobServiceClient(
    `https://${process.env.AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net`,
    sharedKeyCredential
);

const upload = multer({
    storage: multer.memoryStorage(),
});

exports.uploadFile = async (req, res, next) => {
    try{
        const file = req.file;
    if (!file) {
      return res.status(400).json({ error: 'Please upload a file!' });
    }

    // Generate a unique filename using UUID
    const uniqueFileName = `${uuidv4()}-${file.originalname}`;

    // Get a reference to the container
    const containerClient = blobServiceClient.getContainerClient(process.env.AZURE_CONTAINER_NAME);

    // Upload the file to Azure Blob Storage
    const blockBlobClient = containerClient.getBlockBlobClient(uniqueFileName);
    await blockBlobClient.uploadData(file.buffer, {
      blobHTTPHeaders: {
        blobContentType: file.mimetype,
        blobContentDisposition: `attachment; filename="${file.originalname}"`,
      },
    });

    // Save file information to the database
    const newFile = new File({
      filename: file.originalname,
      fileType: file.mimetype,
      fileSize: file.size,
      fileKey: uniqueFileName,
      fileURL: blockBlobClient.url,
    });

    await newFile.save();

    return res.status(201).json({ message: 'File uploaded successfully!', file: newFile });
    } catch (error) {
        console.log(error);
        return res.status(500).json({ error: 'Internal server error!' });
    }
}

I would greatly appreciate any assistance in improving my frontend code for file uploads using fetch(). Additionally, it would be helpful if someone could review my backend code and suggest any potential improvements or debugging steps.

I would greatly appreciate any assistance in improving my frontend code for file uploads using fetch(). Additionally, it would be helpful if someone could review my backend code and suggest any potential improvements or debugging steps.

I would greatly appreciate any assistance improving my frontend code for file uploads using fetch(). Additionally, it would be helpful if someone could review my backend code and suggest any potential improvements or debugging steps.

  • See if the answers to this question help https://stackoverflow.com/questions/50046841/proper-way-to-make-api-fetch-post-with-async-await – Shiraz Bhaiji Jul 30 '23 at 14:58

1 Answers1

0

I made some changes to your frontend code and can able to upload a file as a blob to my storage account container.

Code:

Dashboard.jsx:

import { useState } from 'react';
import axios from 'axios';

export default function FileUploader() {
  const [selectedFile, setSelectedFile] = useState(null);

  const handleFileUpload = async () => {
    if (selectedFile) {
      try {
        const reader = new FileReader();
        reader.readAsDataURL(selectedFile);
        reader.onloadend = async () => {
          const base64File = reader.result.split(',')[1];

          await axios.post('/api/upload', { base64File, filename: selectedFile.name });
        };
      } catch (error) {
        console.error(error);
      }
    }
  };

  const handleFileChange = (event) => {
    const file = event.target.files[0];
    setSelectedFile(file);
  };

  return (
    <div>
      <input type="file" accept=".txt" onChange={handleFileChange} />
      <button onClick={handleFileUpload}>Upload File to storage account</button>
    </div>
  );
}

upload.js:

import { BlobServiceClient } from '@azure/storage-blob';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    try {
      const { base64File, filename } = req.body; 

      const storageAccount = '<storage_name>';
      const containerName = '<container_name>';
      const accessKey = '<storage_key>'; 
      const connectionString = `<connec_string>`;

      const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString);

      const containerClient = blobServiceClient.getContainerClient(containerName);
      const fileBuffer = Buffer.from(base64File, 'base64');
      const blockBlobClient = containerClient.getBlockBlobClient(filename);
      await blockBlobClient.uploadData(fileBuffer, { blobHTTPHeaders: { blobContentType: 'text/plain' } });

      res.status(200).json({ message: 'File uploaded successfully' });
    } catch (error) {
      res.status(500).json({ error: 'Error occurred' });
    }
  } else {
    res.status(405).json({ error: 'Method not allowed' });
  }
}

index.js:

import FileUploader from '../components/Dashboard';

export default function Home() {
  return (
    <div>
      <h1>File Upload</h1>
      <FileUploader />
    </div>
  );
}

Output:

It runs successfully as below,

enter image description here

With the above output URL, I got below at browser. I click on Choose file to choose a file that I want to upload as a blob and click on Upload File to storage account ,

enter image description here

The file uploaded successfully to my storage account container as a blob as below,

enter image description here

Dasari Kamali
  • 811
  • 2
  • 2
  • 6