4

I have node.js application with frontend in Angular I need to upload files and images to Azure blob I have created container and setup the environment according to MS documentation (https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-nodejs )

the v12 version.

My functions works for creating and uploading the created file to Azure blob, I could not figure how do I upload the posted file from the client to Azure Blob, below is my code in Node.js TypeScript

  import * as formidable from 'formidable';
  import * as fs from 'fs';

  const { BlobServiceClient } = require('@azure/storage-blob');
  const uuidv1 = require('uuid/v1');
  const dotenv = require('dotenv');
  dotenv.config();

class BlobController {

    private AZURE_STORAGE_CONNECTION_STRING = process.env.CONSTRINGBlob;

   constructor(router) {
    router.post('/file', this.uploadFile.bind(this));
  }
 //----Get Lookup tables dynamically-----------//
 async uploadFile(req, res) {

    const blobServiceClient = await BlobServiceClient.fromConnectionString(this.AZURE_STORAGE_CONNECTION_STRING);
    // Create a unique name for the container
    //const containerName = 'quickstart' + uuidv1();
    const containerName = blobServiceClient.getContainerClient('mycontainer');
    console.log('\t', containerName.containerName);
    // Get a reference to a container
    const containerClient = await blobServiceClient.getContainerClient(containerName.containerName);
    let form = new formidable.IncomingForm();
    form.parse(req, async function (err, fields, files) {
        const blobName = 'test' + uuidv1() + files.file;
        // Get a block blob client
        const blockBlobClient = containerClient.getBlockBlobClient(blobName);
        console.log('\nUploading to Azure storage as blob:\n\t', blobName);
        // Upload data to the blob
        const data = 'Hello test';
        const uploadBlobResponse = await blockBlobClient.upload(data, data.length);
        console.log("Blob was uploaded successfully. requestId: ", uploadBlobResponse.requestId);
    });
 }
}

module.exports = BlobController

could anyone help me on how can I upload files posted to Azure blob using Node.js

3 Answers 3

4

You were almost there :).

Please change your following code:

form.parse(req, async function (err, fields, files) {
        const blobName = 'test' + uuidv1() + files.file;
        // Get a block blob client
        const blockBlobClient = containerClient.getBlockBlobClient(blobName);
        console.log('\nUploading to Azure storage as blob:\n\t', blobName);
        // Upload data to the blob
        const data = 'Hello test';
        const uploadBlobResponse = await blockBlobClient.upload(data, data.length);
        console.log("Blob was uploaded successfully. requestId: ", uploadBlobResponse.requestId);
    });

to:

  form.parse(req, async function (err, fields, files) {
    const file = files.file;
    const blobName = 'test' + uuidv1() + files.file;
    const contentType = file.type;
    const filePath = file.path;//This is where you get the file path.
    const blockBlobClient = containerClient.getBlockBlobClient(blobName);
    const uploadBlobResponse = await blockBlobClient.uploadFile(filePath);
  });
Sign up to request clarification or add additional context in comments.

3 Comments

Don't understand how this is accepted answer, question clearly states files and images comes from angular client so your solution is to call function which require filePath in nodejs server! This filePath doesn't exist.
@VinKrish - When you use form to handle file uploads, it automatically saves the uploaded content in a temporary file and file.path property gives you the full path of that temporary file. You don't need to do anything special. Do give this code a try. HTH.
I found a better solution, pipe the input stream into azure upload function. Getting file path is tricky when our implementation involves containers and lambda functions.
1
//Here's my form.parse code I used to upload pictures.

form.parse(req, async (err: any, fields: any, files: any) => {        
    const file = files.file;
    const filePath = file.path;//This is where you get the file path. (this is the file itself)
    const blobName: string = slugify(file.name);

    const blockBlobClient = containerClient.getBlockBlobClient(blobName);

    const uploadBlobResponse = await blockBlobClient.uploadFile(filePath)
    console.log("Blob was uploaded successfully. requestId: ", uploadBlobResponse)
    
    if (err) return reject(err)
    //write to DB
    //end write to DB
    resolve(fields)
})

Comments

0

For anyone trying to make use of streams, this worked for me:

import formidable from 'formidable';
import { PassThrough } from 'stream';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method == 'POST') {
        const stream = new PassThrough();
        const form = new formidable.IncomingForm({
            fileWriteStreamHandler: () => {
                return stream;
            }
        });
        form.parse(req, (err, fields, files) => {
            if (files) {
                if (files['<form-file-input-name>']) {
                    const file = files['<form-file-input-name>'] as formidable.File;
                    const mimeType = file.mimetype;
                    const extension = file.originalFilename ? file.originalFilename.substring(file.originalFilename.lastIndexOf('.')) : '.csv';
                    const newFileName = `<form-file-input-name>-${new Date().toISOString()}${extension}`;
                    getFilesBlobContainer().getBlockBlobClient(newFileName).uploadStream(stream, undefined, undefined, {
                        blobHTTPHeaders: {
                            blobContentType: mimeType,
                        },
                    });
                }
            }
        });
        return res.status(200).end();
    }
}

export const config = {
    api: {
        bodyParser: false, //Disable NextJS body parsing so formidable can do that itself (fails silently otherwise)
    },
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.