2

I'm using NestJS, Node, and Express for my backend and Angular for my frontend. I have a stepper where the user steps through and enters in information about themselves as well as a profile photo and any photos of their art that they want to post (it's a rough draft). I'm sending the files to the backend with this code:

<h2>Upload Some Photos</h2>
<label for="singleFile">Upload file</label>

<input id="singleFile" type="file" [fileUploadInputFor]=   "fileUploadQueue"/>
<br>

<mat-file-upload-queue #fileUploadQueue
    [fileAlias]="'file'"
    [httpUrl]="'http://localhost:3000/profile/artPhotos'">

    <mat-file-upload [file]="file" [id]="i" *ngFor="let file of fileUploadQueue.files; let i = index"></mat-file-upload>
</mat-file-upload-queue>

The front-end sends the photos as an array of files; I tried to change it so that it just sent a single file but could not get it working. I'm less focused on that because the user may need to upload multiple files, so I want to figure it out regardless. On the backend, I'm using multer, multer-s3, and AWS-SDK to help upload the files however it isn't working. Here is the controller code:

 @Post('/artPhotos')
    @UseInterceptors(FilesInterceptor('file'))
    async uploadArtPhotos(@Req() req, @Res() res): Promise<void> {
        req.file = req.files[0];
        delete req.files;
        // tslint:disable-next-line:no-console
        console.log(req);
        await this._profileService.fileupload(req, res);
    }

Here is ProfileService:

import { Profile } from './profile.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ProfileDto } from './dto/profile.dto';
import { Req, Res, Injectable, UploadedFile } from '@nestjs/common';
import * as multer from 'multer';
import * as AWS from 'aws-sdk';
import * as multerS3 from 'multer-s3';

const AWS_S3_BUCKET_NAME = 'blah';
const s3 = new AWS.S3();
AWS.config.update({
  accessKeyId: 'blah',
  secretAccessKey: 'blah',
});


@Injectable()
export class ProfileService {

  constructor(@InjectRepository(Profile)
  private readonly profileRepository: Repository<Profile> ){}

  async createProfile( profileDto: ProfileDto ): Promise<void> {
    await this.profileRepository.save(profileDto);
  }

  async fileupload(@Req() req, @Res() res): Promise<void> {
    try {
      this.upload(req, res, error => {
        if (error) {
          // tslint:disable-next-line:no-console
          console.log(error);
          return res.status(404).json(`Failed to upload image file: ${error}`);
        }
        // tslint:disable-next-line:no-console
        console.log('error');
        return res.status(201).json(req.file);
      });
    } catch (error) {
      // tslint:disable-next-line:no-console
      console.log(error);
      return res.status(500).json(`Failed to upload image file: ${error}`);
    }
  }

  upload = multer({
    storage: multerS3({
      // tslint:disable-next-line:object-literal-shorthand
      s3: s3,
      bucket: AWS_S3_BUCKET_NAME,
      acl: 'public-read',
      // tslint:disable-next-line:object-literal-shorthand
      key: (req, file, cb) => {
        cb(null, `${Date.now().toString()} - ${file.originalname}`);
      },
    }),
  }).array('upload', 1);
}

I haven't implemented any middleware extending multer, but I don't think I have to. You can see in the controller I erase the files property on req and replace it with the file where it's value is just the first member of the files array but that was just to see if it would work if I send it something it was expecting, but it did not work then. Does anyone have any ideas regarding how I can fix this? Or can anyone at least point me in the right direction with a link to a relevant tutorial or something?

2 Answers 2

8

My first guess would be that you are using the FileInterceptor and multer. I assume FileInterceptor adds multer in the controller which makes it available to the @UploadedFile decorator. Which could cause a conflict to your later use of multer. Try removing the interceptor and see if that fixes the issue.

Also I am attaching how I am doing file uploads. I am only uploading single images and I am using the AWS SDK so I don't have to work with multer directly, but here is how I am doing it, it might be helpful.

In the controller:

  @Post(':id/uploadImage')
  @UseInterceptors(FileInterceptor('file'))
  public uploadImage(@Param() params: any, @UploadedFile() file: any): Promise<Property> {
    return this.propertyService.addImage(params.id, file);
}

Then my service

/**
 * Returns a promise with the URL string.
 *
 * @param file
 */
public uploadImage(file: any, urlKey: string): Promise<string> {
  const params = {
    Body: file.buffer,
    Bucket: this.AWS_S3_BUCKET_NAME,
    Key: urlKey
  };

  return this.s3
    .putObject(params)
    .promise()
    .then(
      data => {
        return urlKey;
      },
      err => {
        return err;
      }
    );
}
Sign up to request clarification or add additional context in comments.

5 Comments

what is urlKey you are passing to uploadImage function?
The urlKey is the path and name I want the file to have in the S3 bucket. In my case I generate a UUID that I use along with some folders I nest it in. So it might be something like "users/2/0e7b55b7-1e4c-49c4-9a7e-93c526b7fb16" where it will be in the "users" and "2" folders and the filename is "0e7b55b7-1e4c-49c4-9a7e-93c526b7fb16".
do you have any gist that encompasses the upload files module better? I'm having a lot of troubles with mine
@DanutPralea I can't add a lot more but I did throw together a gist with a few more details. gist.github.com/jedsmith13/0c7135ac19af193b893057cf9784550f
@JedediahSmith Could you please help me with this? how can I upload file as part of form. once user click on submit button file should also be saved. would be always greatful. stackoverflow.com/questions/69849722/…
0

Thanks Jedediah, I like how simple your code is. I copied your code however it still wasn't working. Turns out you have to instantiate the s3 object after you update the config with your accesskey and secretID.

2 Comments

would you mind pasting the file upload module here, or anywhere? I'm having the exact same issues as you and I've spent countless hours trying to fix it.

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.