VitNode

Upload Files

How to upload files to the system.

We know how important it is to be able to upload files to the system. Our functions can help you implement upload files with ease.

Storage files outside local

For now VitNode only supports local storage for files. We'll be working on supporting other storage options like S3, Google Cloud Storage, etc. in the feature.

Create DTO

First of all, you need to create a DTO to handle the file upload.

example.dto.ts
import { ApiProperty } from '@nestjs/swagger';
 
export class ShowMetadataAdminBody {
  @ApiProperty({ type: 'string', format: 'binary' })
  icon: Express.Multer.File;
}

Create Controller

Create a controller to handle the file upload. Use the @UploadFilesMethod decorator to handle the file upload and pass all files name in the fields array.

This decorator will automatically change consumers to multipart/form-data and handle the files upload.

example.controller.ts
import { Put } from '@nestjs/common';
import { UploadFilesMethod } from 'vitnode-backend/helpers/upload-files.decorator'; 
 
export class MetadataAdminController {
  @Put()
  @ApiOkResponse({
    description: 'Edit metadata settings',
    type: ShowMetadataAdminObj,
  })
  @UploadFilesMethod({ fields: ['icon'] }) 
  async edit(): Promise<ShowMetadataAdminObj> {}
}

Get files form body

To get the files from the body, you can use the @UploadedFiles decorator with FilesValidationPipe to validate the files. As an example below, we validate the icon field with a maximum size of 1MB, accept only image files, and allow only one file.

example.controller.ts
import { Put } from '@nestjs/common';
import { UploadFilesMethod } from 'vitnode-backend/helpers/upload-files.decorator';
import { FilesValidationPipe } from 'vitnode-backend/helpers/files/files.pipe'; 
 
export class MetadataAdminController {
  @Put()
  @ApiOkResponse({
    description: 'Edit metadata settings',
    type: ShowMetadataAdminObj,
  })
  @UploadFilesMethod({ fields: ['icon'] })
  async edit(

    @UploadedFiles(

      new FilesValidationPipe({

        icon: {

          maxSize: 1024 * 1024, // 1 MB

          acceptMimeType: [

            'image/png',

            'image/jpeg',

            'image/svg+xml',

            'image/webp',

          ],

          maxCount: 1,

        },

      }),

    )
    files: Pick<ShowMetadataAdminBody, 'icon'>, 
  ): Promise<ShowMetadataAdminObj> {}
}

Below you can see other options for the FilesValidationPipe:

example.controller.ts
export class MetadataAdminController {
  async edit(
    @UploadedFiles(
      new FilesValidationPipe({
        icon: {
          maxSize: 1024 * 1024, // 1 MB
          acceptMimeType: [
            'image/png',
            'image/jpeg',
            'image/svg+xml',
            'image/webp',
          ],
          maxCount: 1, 
        },
      }),
    )
    files: Pick<ShowMetadataAdminBody, 'icon'>,
  ): Promise<ShowMetadataAdminObj> {}
}

Handle upload files

Now you can handle the upload files in your service. As an example we will add files and also body data.

example.controller.ts
export class MetadataAdminController {
  constructor(private readonly editService: EditMetadataAdminService) {}
 
  async edit(
    @UploadedFiles(
      new FilesValidationPipe({
        icon: {
          maxSize: 1024 * 1024, // 1 MB
          acceptMimeType: [
            'image/png',
            'image/jpeg',
            'image/svg+xml',
            'image/webp',
          ],
          isOptional: true,
          maxCount: 1,
        },
      }),
    )
    files: Pick<ShowMetadataAdminBody, 'icon'>,
    @Body() body: ShowMetadataAdminBody,
  ): Promise<ShowMetadataAdminObj> {
    return this.editService.edit({ body, files }); 
  }
}

Below you can see the service example:

example.service.ts
@Injectable()
export class EditMetadataAdminService {
  async edit({
    body,
    files,
  }: {
    body: Omit<ShowMetadataAdminBody, 'icon'>; 
    files: Pick<ShowMetadataAdminBody, 'icon'>; 
  }): Promise<ShowMetadataAdminObj> {}
}

We omit the icon field from the body because any file doesn't exist in the body. We need to handle the file separately.

Upload file

Now you can upload the files to the storage by using the FilesHelperService and the upload method.

example.service.ts
import { FilesHelperService } from 'vitnode-backend/helpers/files/files-helper.service'; 
 
@Injectable()
export class EditMetadataAdminService {
  constructor(private readonly filesHelper: FilesHelperService) {} 
 
  async edit({
    body,
    files,
  }: {
    body: Omit<ShowMetadataAdminBody, 'icon'>;
    files: Pick<ShowMetadataAdminBody, 'icon'>;
  }): Promise<ShowMetadataAdminObj> {

    const uploadObj = await this.filesHelper.upload({
      file: files.icon, 
      folder: 'manifest', 
      plugin_code: 'core', 

    });
  }
}

Secure file

As default each files will save as public and will be visible for everyone. If you want to save the file as secure, you can pass the secure option as true.

example.service.ts
const uploadObj = await this.filesHelper.upload({
  file: files.icon,
  folder: 'manifest',
  plugin_code: 'core',
  secure: true, 
});

Secure files will be saved in a private folder inside uploads folder in backend and will be accessible only by the system. You need to handle the access to the file by yourself.

Handle the response

filesHelper.upload will return an object with the following properties:

  • dir_folder - The folder where the file is saved.
  • extension - The file extension.
  • file_name - The file name.
  • file_name_original - The original file name.
  • file_size - The file size in bytes.
  • height - The height of the image file.
  • mimetype - The file mimetype.
  • secure - If the file is secure.
  • width - The width of the image file.

Default URL for the public file will be: {backend_url}/public/{dir_folder}/{file_name}.

VitNode will not save any information about the file. You need to handle the file information by yourself for example in the database.

Delete file

To remove the file, you can use the FilesHelperService and the delete method.

example.service.ts
await this.filesHelper.delete({
  dir_folder: file.icon.dir_folder,
  file_name: file.icon.file_name,
});

Delete secure file

If you want to delete a secure file, you need to pass the secure option as true.

example.service.ts
await this.filesHelper.delete({
  dir_folder: file.icon.dir_folder,
  file_name: file.icon.file_name,
  secure: true, 
});

On this page