Fastify + NestJS file upload
Tags: javascript, tutorial, programming, typescript
Published: 2023-10-28 17:02:51

We all know that Fastify is faster than Express, and for this reason, many people are switching from the Express micro-framework to Fastify. However, sometimes you might want to build a more robust system with better tooling. In such cases, you can choose between Meteor, Adonis, or NestJS. Many developers opt for NestJS because it is reminiscent of SpringBoot from Java and is built on top of Express. However, it also offers compatibility with Fastify, providing developers with the best of both worlds.

I always choose NestJS with Fastify, it works incredibly well in most cases. However, even though NestJS offers full support for Fastify, not everything is rosy, uploading files can be a little bit tricky in a NestJS environment powered by Fastify. So, in this article, I am gonna teach you how to do this, as it is not present in the official docs.

## Installing the dependencies

First, you need to install the necessary packages. You can do this using your preferred package manager. Here are the packages you need:

- `@fastify/multipart`
- `@blazity/nest-file-fastify`

To install the packages, run one of the following commands:

`yarn add @fastify/multipart @blazity/nest-file-fastify`

or

`npm install @fastify/multipart @blazity/nest-file-fastify`

## Modify your `main.ts` file

1. Import the @fastify/multipart package
2. Register the package within Fastify

The code should look something like this:

```tsx
// other imports
import multiPart from '@fastify/multipart';

/**
 * Main function
 */
async function bootstrap(): Promise<void> {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter({
      logger: true,
    }),
  );
	
	await app.register(multiPart);
  const httpAdapterHost = app.get(HttpAdapterHost);

	// rest of the code ...

  await app.listen(3333, process.env.HOST);
}
```

## Create a route for uploading files in a NestJS controller

Now, you need to create a controller with a route for handling file uploads. Here’s an example of how you can do it:

```tsx
import {
  FileFieldsInterceptor,
  MemoryStorageFile,
  UploadedFiles,
} from '@blazity/nest-file-fastify';
import {
  Body,
  Controller,
  Post,
  UseInterceptors,
} from '@nestjs/common';

@Controller('example')
export class ExampleController {

	/**
   * Route for uploading files
   */
  @Post('/upload')
  @UseInterceptors(
    FileFieldsInterceptor([
      { name: 'image', maxCount: 1 },
      { name: 'imageTwo', maxCount: 1 },
    ])
  )
  async register(
    @Body() data: Record<string, unknown>,   // other data that you might want to pass along with the files
    @UploadedFiles()
    files: { image?: MemoryStorageFile[0]; imageTwo?: MemoryStorageFile[0] }
  ): Promise<void> {
    Object.values(files).forEach((file) => {
      this.s3Service.uploadFile(file[0]);
    });
  }

}
```

In this example, the `@Post('/upload')` route is set up to handle file uploads. The FileFieldsInterceptor is used to specify the expected file fields in the request. In this case, we expect two image files, image, and imageTwo, each with a maximum count of 1.

The uploaded files are then passed to the register method, where they can be processed as needed. In this example, the files are uploaded to an S3 service.

That’s it! Now you can send a multipart/form-data request to your NestJS server, and the files will be handled accordingly.