fastify-file-interceptor

This library for Nest.js using FastifyAdapter it rely on library fastify-multer and express multer

Usage no npm install needed!

<script type="module">
  import fastifyFileInterceptor from 'https://cdn.skypack.dev/fastify-file-interceptor';
</script>

README

Installation

npm install fastify-file-interceptor
yarn add fastify-file-interceptor
FileFastifyInterceptor() may not be compatible with third party cloud providers like Google Firebase or others. This package is base on NestJs ,fastify-multer

/* main.ts */
import "reflect-metadata";
import {
  FastifyAdapter,
  NestFastifyApplication,
} from "@nestjs/platform-fastify";
import { join } from "path";
// update you can import from "fastify-file-interceptor"
import { contentParser, MulterFile } from "fastify-file-interceptor";

async function bootstrap(): Promise<void> {
  const app =
    (await NestFactory.create) <
    NestFastifyApplication >
    (AppModule, new FastifyAdapter());
  await app.listen(3000);

  app.register(contentParser);

  /* yarn add fastify-static */
  app.useStaticAsset({ root: join(__dirname, "../../example") });
}
bootstrap();
/* app.controller.ts */
import {
  Body,
  Controller,
  Post,
  UploadedFile,
  UploadedFiles,
  UseInterceptors,
} from "@nestjs/common";
import { ApiConsumes, ApiTags } from "@nestjs/swagger";
import { diskStorage } from "multer";
import { AppService } from "./app.service";
import {
  MultipleFileDto,
  SingleFileDto,
  AnyFileDto,
  FieldsFileDto,
} from "./dto/re-export-dto";
import { editFileName, imageFileFilter } from "./utils/file-upload-util";
import {
  AnyFilesFastifyInterceptor,
  FileFastifyInterceptor,
  FileFieldsFastifyInterceptor,
  FilesFastifyInterceptor,
} from "fastify-file-interceptor";
@Controller()
@ApiTags("Upload File ")
export class AppController {
  constructor(private readonly appService: AppService) {}

  // Single File
  @ApiConsumes("multipart/form-data")
  @Post("single-file")
  @UseInterceptors(
    FileFastifyInterceptor("photo_url", {
      storage: diskStorage({
        destination: "./upload/single",
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
    })
  )
  single(@UploadedFile() file: MulterFile, @Body() body: SingleFileDto) {
    console.log({ ...body, photo_url: file });
    return { ...body, photo_url: file };
  }

  // Multiple File
  @ApiConsumes("multipart/form-data")
  @Post("multiple-file")
  @UseInterceptors(
    FilesFastifyInterceptor("photo_url", 10, {
      storage: diskStorage({
        destination: "./upload/multiple",
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
    })
  )
  multiple(
    @UploadedFiles() files: MulterFile[],
    @Body() body: MultipleFileDto
  ) {
    console.log({ ...body, photo_url: files });
    return { ...body, photo_url: files };
  }

  // Any File
  @ApiConsumes("multipart/form-data")
  @Post("any-file")
  @UseInterceptors(
    AnyFilesFastifyInterceptor({
      storage: diskStorage({
        destination: "./upload/any",
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
    })
  )
  anyFile(@UploadedFiles() files: MulterFile, @Body() body: AnyFileDto) {
    console.log({ ...body, photo_url: files });
    return { ...body, photo_url: files };
  }

  // File Field
  @ApiConsumes("multipart/form-data")
  @Post("fields-file")
  @UseInterceptors(
    FileFieldsFastifyInterceptor(
      [
        {
          name: "photo_url",
          maxCount: 10,
        },
        {
          name: "images",
          maxCount: 10,
        },
      ],
      {
        storage: diskStorage({
          destination: "./upload/fields",
          filename: editFileName,
        }),
        fileFilter: imageFileFilter,
      }
    )
  )
  fields(@UploadedFiles() { photo_url, images }, @Body() body: FieldsFileDto) {
    console.log({ ...body, photo_url, images });
    return { ...body, photo_url, images };
  }
}

NOTE property destination inside diskStorage is the location in our project directory where we want to store the image

file-upload-util.ts

import { Request } from "express";
import { extname } from "path";

export const editFileName = (req: Request, file: MulterFile, callback) => {
  const name = file.originalname.split(".")[0];
  const fileExtName = extname(file.originalname);
  callback(null, `${name}${fileExtName}`);
};

export const imageFileFilter = (req: Request, file: MulterFile, callback) => {
  if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
    return callback(new Error("Only image files are allowed!"), false);
  }
  callback(null, true);
};

Hint save image as CDN and display in browser

/* file-mapper.ts */
import { FastifyRequest } from "fastify";

interface FileMapper {
  file: Express.Multer.File;
  req: FastifyRequest;
}

interface FilesMapper {
  files: Express.Multer.File[];
  req: FastifyRequest;
}

export const fileMapper = ({ file, req }: FileMapper) => {
  const image_url = `${req.protocol}://${req.headers.host}/${file.path}`;
  return {
    originalname: file.originalname,
    filename: file.filename,
    image_url,
  };
};

export const filesMapper = ({ files, req }: FilesMapper) => {
  return files.map((file) => {
    const image_url = `${req.protocol}://${req.headers.host}/${file.path}`;
    return {
      originalname: file.originalname,
      filename: file.filename,
      image_url,
    };
  });
};

Usage

if you already know how to use function from "@nestjs/platform-express" it's the same.

"fastify-file-interceptor";

import {
  AnyFilesFastifyInterceptor,
  FileFastifyInterceptor,
  FileFieldsFastifyInterceptor,
  FilesFastifyInterceptor,
} from "fastify-file-interceptor";
"@nestjs/platform-express";

import {
  AnyFilesInterceptor,
  FileFieldsInterceptor,
  FileInterceptor,
  FilesInterceptor,
} from "@nestjs/platform-express";

You can install example test on swagger Example Repo on github: https://github.com/chanphiromsok/example-fastify-file-interceptor