Handling File Uploads with NestJS and MySQL
Tags: programming, nestjs, mysql, tutorial
Published: 2022-08-02 22:17:32

## Introduction

Many developers despise dealing with file uploads. This can be attributed to a lack of knowledge about the best approach to take or difficulties determining how to configure their Nest.js application to handle file uploads. Many people may want to save their files directly to a MySQL database, or save image names and have the image saved on disk storage: it all depends on their preferences and the goals they want to achieve. This tutorial will teach you how to build a file uploading functionality using Nestjs and MySQL.

## Prerequisites

Before you begin following this tutorial, ensure your system meets the following requirements:

- Your system is running [Node.js](https://nodejs.org/en/download/) with version 14 or later.
- Your system has a [MySQL database](https://www.mysql.com/downloads/) installed.
- You have installed [Postman](https://www.postman.com/).

## Setting Up NestJS

Once the above-mentioned requirements are met, proceed to install the Nestjs CLI and create a new project by running the following commands:

    $ npm i -g @nestjs/cli
    $ nest new file-upload

These commands will install the Nestjs CLI and create a new Nestjs project with the folder structure below.


![](https://cdn.hashnode.com/res/hashnode/image/upload/v1659478229482/2JLaklpjN.png align="left")

After the Nestjs project has been created, move on to the next step - install the required dependencies for your application by running the following command:

    npm install --save @nestjs/typeorm typeorm mysql2
    

In the above command, you’ve installed the [TypeORM](https://typeorm.io/) and [mysql2](https://github.com/brianmario/mysql2) modules: they will enable you to connect your application to a MySQL database and perform operations on it.

## Setup the MySQL Database

With the above dependencies installed, proceed to set up and connect to your MySQL database. To get started, add the code in the `app.module.ts` file with the code snippet below.

    ...
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { Image } from './image.entity';
    
    @Module({
      imports: [TypeOrmModule.forRoot({
        type: 'mysql',
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: '1234',
        database: 'blog',
        entities: [Image],
        synchronize: true,
      }),
      TypeOrmModule.forFeature([Image])
      ],
      ...
    })
    ...

In the above code snippet, we imported `TypeOrmModule` from the typeorm module we installed earlier. We used the `forRoot` method to connect the application to a MySQL database and pass in the database credentials. Another thing to point out here is that `entities` properties, which allowed us to specify the entities in our module and which will give us access to the `Image` entity you’ll be creating shortly: we also have the `synchronize` property set to `true` to automatically migrate the database.

## Create Image Entity

Next, let’s create the Image entity we mentioned earlier. To get started, create a image.entity.ts file in the src directory and add the code snippet below.

    import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
    
    @Entity()
    export class Image {
        @PrimaryGeneratedColumn()
        id: number;
    
        @Column()
        name: string;
    
        @CreateDateColumn()
        dateCreated: Date;
    
        @UpdateDateColumn()
        dateUpdated: Date;
    }

In the above code snippet, we imported the decorators we need to create an entity. Using these decorators we defined the properties of the entity. We have the `id` field to generate random id’s for each record in the database using the `@PrimaryGeneratedColumn()` decorator, the `name` field to store the names of the images that will be uploaded using the `@Column` decorator, the dateCreated and dateUpdate fields to save the date a record was created and updated using the `@CreateDateColumn()` and `@UpdateDateColumn()`.

## Creating the Upload Service

With the Image entity created, let’s create a service to perform the CRUD operations to handle the file uploads. In the `app.service.ts` file, add the code snippet below.

    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { Repository } from 'typeorm';
    import { Image } from './image.entity';
    
    @Injectable()
    export class AppService {
      constructor(
        @InjectRepository(Image)
        private readonly imageRepository: Repository<Image>,
      ) {}
    
      async getImages(): Promise<Image[]> {
        return this.imageRepository.find();
      }
    
      async createImage(image: Image): Promise<Image> {
        return this.imageRepository.save(image);
      }
    
      async getImage(id: number): Promise<Image> {
        return this.imageRepository.findOneBy({ id });
      }
    
      async deleteImage(id: number): Promise<void> {
        await this.imageRepository.delete(id);
      }
    }
    

In the above code snippet, we have imported the `injectRepository` decorator to inject the `imageRepository` into `AppService` and the `Repository` which provides you with the methods required to perform some operations on your database. So for the `createImage` image service, we are saving the name of the image that is been uploaded which will be passed through the controller.

## Creating the Upload Controller

Now let’s create the controllers to use the services. In the `app.controller.ts` file and add the code snippet below.

    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { Repository } from 'typeorm';
    import { Image } from './image.entity';
    
    @Injectable()
    export class AppService {
      constructor(
        @InjectRepository(Image)
        private readonly imageRepository: Repository<Image>,
      ) {}
    
      async getImages(): Promise<Image[]> {
        return this.imageRepository.find();
      }
    
      async createImage(image: Image): Promise<Image> {
        return this.imageRepository.save(image);
      }
    
      async getImage(id: number): Promise<Image> {
        return this.imageRepository.findOneBy({ id });
      }
    
      async deleteImage(id: number): Promise<void> {
        await this.imageRepository.delete(id);
      }
    }
    

In the above code snippet, we imported a couple of decorators like `FileInterceptor`, `UploadedFile`, and `UseInterceptors`. The `FileInterceptor()` interceptor to the route handler extracts the file from the request using the `@UploadedFile()` decorator. The `FileInterceptor()` decorator is exported from the `@nestjs/platform-express` package. The `@UploadedFile()` decorator is exported from `@nestjs/common`. The `FileInterceptor()` decorator takes two arguments, `fieldName` which is the string that supplies the name of the field from the HTML form that holds a file, and the `options` which is an optional object of type MulterOptions. This is the same object used by the multer constructor.

Regarding the `createImage` function, we have used the aforementioned decorators to handle the file upload using the `FileInterceptor()` passing the field name for the image and we modified the `FileInterceptor()` function to upload the image to disk by specifying the `storage` property using the `diskStorage` function available in `multer`. Then we specified the location for the images and generated random names for the images. Also, we added a `filter` property to restrict the upload of certain image formats. Now we get the file extracted using the `@UploadedFile()` decorator and get the name and save it to the database. This way we can use the name of each image to get the image from the storage location.

For the above code to work, you need to install multer by running the command below in your terminal:

    npm i -D @types/multer
    

Then, you need to register the multer module in the array of imports in the `app.module.ts` file:

    ...
    import { MulterModule } from '@nestjs/platform-express';
    
    
    @Module({
      ...
      MulterModule.register({
        dest: './files',
      }),],
      ...

The above configuration tells multer to handle the file upload and the location to upload the file to. Last but not least, we should create a `files` folder in the `src` directory to actually store the files.

## Serving Files

To actually serve the images uploaded on your application to the user, you need to install the `serve-static` module by running the command below.

    npm install --save @nestjs/serve-static
    

Then, register the `ServeStaticModule` in the array of imports in the `app.module.ts` file with the code snippet below.

    ...
    import { ServeStaticModule } from '@nestjs/serve-static';
    import { join } from 'path';
    
    @Module({
      ...
      ServeStaticModule.forRoot({
        rootPath: join(__dirname, '..', 'files')
      }),],
      ...
    

In the above code snippet, you’ve specified the location where the files are located and can be served from.

## Testing the API

Now open Postman and test the application by sending a POST request to the endpoint `localhost:4000/images`, and pass in the payload in the request body as a form-data.

![](https://arctype.com/blog/content/images/2022/08/image.png)

If you now look at the files folder, you should see the file you have uploaded. Feel free to go ahead: test and play around with other routes as well.

## Conclusion

Through this tutorial, you’ve learned how to handle file upload with NestJS and MySQL. You’ve learned how to connect to a MySQL database using TypeORM and you have also created an entity and uploaded images to the Nestjs application.

You've successfully built a file upload feature with NestJS and MySQL: for the future of your database and application, though, keep in mind that keeping a constant eye on your applications and databases consists of much more than building features for them: [SQL clients like Arctype](https://arctype.com) will let you write SQL queries and optimize them as well as visualize the data currently existing in your database, and [the content existing on the Arctype blog](https://arctype.com/blog) will let you learn how to [optimize all of your MySQL instances for security, availability, and performance](__GHOST_URL__/mysql-storage-engine-big-data/) at ease as well as provide you with lots of insight in regards to the database world as a whole.

For further reading, you can also read more about uploading files in [Nestjs](https://docs.nestjs.com/techniques/file-upload). For an extra challenge, try extending the application by protecting the delete and update routes. What will you build next?