Failing to retrieve the file instance upon completing the upload process to cloudinary using nestjs

I am attempting to retrieve the secure file URL provided by Cloudinary after successfully uploading the asset to their servers. Although I can upload the file to Cloudinary, when I try to view the response using console.log(res), I unfortunately receive 'undefined'.

Codes :-

// cloudinary.service.ts
import { Injectable } from '@nestjs/common';
import { UploadApiErrorResponse, UploadApiResponse, v2 } from 'cloudinary';
import toStream = require('buffer-to-stream');
import { ConfigService } from '@nestjs/config';

@Injectable()
export class CloudinaryService {
    constructor(private configService: ConfigService) {}
    async uploadMedia(
        file: Express.Multer.File,
    ): Promise<UploadApiResponse | UploadApiErrorResponse> {
        return new Promise((resolve, reject) => {
            const upload = v2.uploader.upload_stream(
                {
                    upload_preset: this.configService.get('CLOUDINARY_UPLOAD_PRESET'),
                },
                (error, result) => {
                    if (error) return reject(error);
                    resolve(result);
                },
            );
            toStream(file.buffer).pipe(upload);
        });
    }
}
// cloudinary.module.ts
import { Module } from '@nestjs/common';
import { CloudinaryProvider } from './cloudinary.provider';
import { CloudinaryService } from './cloudinary.service';
import { ConfigModule } from '@nestjs/config';

@Module({
    imports: [ConfigModule],
    providers: [CloudinaryProvider, CloudinaryService],
    exports: [CloudinaryProvider, CloudinaryService],
})
export class CloudinaryModule {}
// cloudinary.provider.ts
import { v2 } from 'cloudinary';
export const CloudinaryProvider = {
    provide: `${process.env.CLOUDINARY_PROVIDER_TOKEN}`,
    useFactory: () => {
        return v2.config({
            cloud_name: `${process.env.CLOUDINARY_CLOUD_NAME}`,
            api_key: `${process.env.CLOUDINARY_API_KEY}`,
            api_secret: `${process.env.CLOUDINARY_API_SECRET}`,
        });
    },
};
// media.controller.ts
import {
    Controller,
    Post,
    UploadedFile,
    UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { MediaService } from './media.service';

@Controller('media')
export class MediaController {
    constructor(private mediaService: MediaService) {}

    @Post('upload')
    @UseInterceptors(FileInterceptor('file'))
    upload(@UploadedFile() file: Express.Multer.File) {
        return this.mediaService.uploadMediaToCloudinary(file);
    }
}
// media.service.ts
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CloudinaryService } from '../cloudinary/cloudinary.service';

@Injectable()
export class MediaService {
    constructor(private cloudinaryService: CloudinaryService) {}

    async uploadMediaToCloudinary(file: Express.Multer.File) {
        return await this.cloudinaryService.uploadMedia(file).catch(error => {
            throw new HttpException(
                {
                    message: error.message,
                },
                HttpStatus.INTERNAL_SERVER_ERROR,
            );
        });
    }
}
// media.module.ts
import { Module } from '@nestjs/common';
import { CloudinaryModule } from 'src/cloudinary/cloudinary.module';
import { MediaController } from './media.controller';
import { MediaService } from './media.service';

@Module({
    imports: [CloudinaryModule],
    controllers: [MediaController],
    providers: [MediaService],
})
export class MediaModule {}
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CloudinaryModule } from './cloudinary/cloudinary.module';
import { MediaModule } from './media/media.module';

@Module({
    imports: [
        ConfigModule.forRoot({
            envFilePath: '.env',
        }),
        MongooseModule.forRootAsync({
            imports: [ConfigModule],
            useFactory: async (configService: ConfigService) => ({
                uri: configService.get<string>('MONGO_URI'),
            }),
            inject: [ConfigService],
        }),
        CloudinaryModule,
        MediaModule,
    ],
    controllers: [AppController],
    providers: [AppService],
})
export class AppModule {}

Nestjs File Upload Docs :- https://docs.nestjs.com/techniques/file-upload[enter link description here]1

Testing Client :- https://codesandbox.io/s/file-link-generator-example-app-react-byez4?file=/src/App/UploadFile.js

Answer №1

For a recent project, I needed to implement a file upload feature. Instead of using the upload_stream api, I opted for the Cloudinary upload API. Additionally, I had to encode the file in base64 before sending it from the frontend. Here's the approach I took and it worked successfully.

@Post()
    @UseInterceptors(FileInterceptor('file'))
    async uploadFile(@UploadedFile() file, @Body() body) {

        const dto = JSON.parse(body.reportData);

        if (file) {
            const imageBuffer = await this.encodeImageForCloudinary(file.buffer, file.mimetype);
            const cloudinaryStoredImage = await this.cloudinaryService.uploadImg(imageBuffer);
            dto.imageUrl = cloudinaryStoredImage.url;
        }
        return await this.save(dto);
    }
    async save(@Body() dto) {
        let report = this.mapToEntity(dto);
        report = await this.reportService.add(report);
        return this.mapToDTO(report);
    }

    encodeImageForCloudinary(data, mediaType) {
        if (!data || !mediaType) {
            this.logger.log('ImageDataURI :: Error :: Missing some of the required params: data, mediaType ');
                     return null;
        }

        mediaType = (/\//.test(mediaType)) ? mediaType : 'image/' + mediaType;
        const dataBase64 = (Buffer.isBuffer(data)) ? data.toString('base64') : Buffer.from(data).toString('base64');
        const dataImgBase64 = 'data:' + mediaType + ';base64,' + dataBase64;

        return dataImgBase64;
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for integrating jwt token into axios request

I am facing an issue with my backend endpoint. I can successfully retrieve a list of customers using jwt token on Postman, but when I try to fetch the list from a React app using axios get request, it fails. After reading through this question, I implemen ...

What is the best way to display the value of a PHP variable in a JavaScript pop-up window?

Here are the scripts I have. A user will input a numerical value like 123 as a parameter in the URL, and the application will retrieve that value from MySQL and display it in the textarea. For example, if you enter "example.com/index.php?id=123" in the UR ...

Separate files containing TypeScript decorators are defined within a project

(Let's dive into Typescript and Angular2, shall we?) Having primarily coded in Symfony2 with annotations, I found it convenient to configure entity mapping, routing, and other features using yaml, xml, or plain PHP. This flexibility was great for cre ...

AngularJS Vimeo API Request Error: "401 Authorization Required"

I've been experimenting with making external API calls to Vimeo from my AngularJS code using $http.jsonp. However, I keep receiving a 401 Authorization required error even though I have included my authorization key in the header. I encountered a simi ...

Attempting to transmit information to database using AJAX in the context of CodeIgniter

I'm having some trouble with my AJAX setup. It doesn't seem to be posting any data to the database, despite trying various solutions I found online. That's why I've turned to this platform for help. When testing in Postman and sending ...

Issue: The object is unable to be executed as a function, resulting in the failure to return an array

Currently, I am extracting table values from the UI row by row. This involves clicking on each row and retrieving the corresponding data. exports.getTableData = function(callback){     var uiArray =[];     var count;         aLib.loadCheck(c ...

Mongoose is unable to update arrays, so it will simply create a new array

Having trouble updating my collection without any errors. Can someone lend a hand? I've been at this for 3 hours now. const product_id = req.body.cartItems.product_id; const item = cart.cartItems.find(c => c.product_id == product_id); i ...

How do I adjust the controls in Three.js to align with the previous camera position?

The three.js scene is equipped with W,A,S,D and left and right arrow controls, which allow for movement of the camera. However, the controls restrict the camera's movement to a fixed direction in the scene, rather than relative to its previous positio ...

Tips on converting Nextjs generated Prisma types case from snake_case to camelCase

I have a full-stack application built with Next.js and Prisma ORM "next": "12.3.0" "prisma": "^4.5.0" Essentially, I am looking to convert the case of my types from snake_case to camelCase to align with the front-en ...

Update the nest-cli.json configuration to ensure that non-TypeScript files are included in the dist directory

I've been searching for a solution for hours now: I'm developing an email service using nestJS and nest mailer. Everything was working fine until I tried to include a template in my emails. These templates are hbs files located in src/mail/templ ...

When using Browserify, the function require() on a concatenated string will not include the module in the output script

When using require() to create a combined string path, the path of the module will not be included in the output script. Examples of this include: require("./"+"b" ); //or var path="./"; require(path+"b"); Let's say we have a.js module.exports="a"; ...

Move the cursor to the end of the text when the key is released

I've developed a feature similar to that of a command line interface. When you input commands and hit the up key, the previous command is displayed. Everything is functioning as intended, but there's one minor issue. The current problem I'm ...

Selecting a value from a populated dropdown and checking the corresponding checkbox in SQL Server

There are 8 checkboxes in this example: <table style="border-collapse: collapse; width: 100%;" border="1"> <tbody> <tr style="height: 21px;"> <td style="width: 25%; height: 21px;"><strong>Technology</strong& ...

How can I receive the response from a GET request using React Query? I am currently only able to get the response

I have created a search component where I input a name in the request, receive a response, and display it immediately. However, after the first input submit, I get undefined in response. Only after the second submit do I get the desired response. The tec ...

Get rid of the strange border on the material dialog

I am struggling with the Angular material 6 dialog component as it is displaying a strange border. I have attempted to remove it using the code below, without success. Interestingly, when I apply the style inline in the browser, it works fine. Any suggesti ...

Can you explain the variances between the two Pick<T,K> util type implementations?

Here is a link I am exploring: https://github.com/type-challenges/type-challenges/blob/master/questions/4-easy-pick/README.md I am struggling to grasp the distinction between these two code snippets: type MyPick<T, K> = T extends {} ? K extends keyo ...

Posting Form Data with Ajax in CodeIgniter

Incorporating the CodeIgniter framework along with the jQuery Form plugin available at http://malsup.com/jquery/form/ Encountering challenges in ensuring proper functionality of a form. View <div class="row"> <div class="well c ...

Retrieve the IDs of list elements in order to dynamically update a div using AJAX

I'm facing a bit of a challenge at the moment. I have a webpage that uses jQuery to load three different views: one displaying all categories associated with the user, another showing the image and name of items within the selected category, and a thi ...

What are the possible arguments for the event type onInput?

While diving into the world of html / javascript / vue, I stumbled upon the following code snippet. <input type="text" onInput="doAction(event);"> <script> var mesdata = { message: 'type your m ...

Tips for inserting a blank space into a text box

It feels like such a simple issue, but my function is incorrectly returning "1" instead of just an empty space "" in my textbox. <td><input type="button" value="Space" name="Space" onClick='document.firstChild.search.value = document.firstCh ...