API with NestJS #55. Uploading files to the server

JavaScript NestJS TypeScript

This entry is part 55 of 121 in the API with NestJS

So far, in this series, we’ve described two ways of storing files on a server. In the 10th article, we’ve uploaded files to Amazon S3. While it is very scalable, we might not want to use cloud services such as AWS for various reasons. Therefore, in the 54th part of the series, we’ve learned how to store files straight in our PostgreSQL database. While it has some advantages, it might be perceived as less than ideal in terms of performance.

In this article, we look into using NestJS to store uploaded files on the server. Again, we persist some information into the database, but it is just the metadata this time.

Storing the files on the server

Fortunately, NestJS makes it very easy to store the files on the server. We need to pass additional arguments to the .

users.service.ts

When we do the above, NestJS stores uploaded files in the directory.

There are a few issues with the above approach, though. First, we might need more than one endpoint to accept files. In such a case, we would need to repeat some parts of the configuration for each one of them. Also, we should put the part of the destination in an environment variable to change it based on the environment the app runs in.

Extending the FileInterceptor

A way to achieve the above is to extend the . After looking under the hood of NestJS, we can see that it uses the mixin pattern. Because is not a class, we can’t use the keyword.

We want to extend the functionalities while:

  • having Dependency Injection to inject the ,
  • being able to pass additional properties from the controller.

To do that, we can create our mixin:

localFiles.interceptor.ts

Above, we use the variable and concatenate it with the provided path. To do that, let’s define the necessary environment variable.

app.module.ts

.env

When all of the above is ready, we can use the in our controller:

users.controller.ts

Saving the metadata in the database

Besides storing the file on the server, we also need to save the file’s metadata in the database. Since NestJS generates a random filename for uploaded files, we also want to store the original filename. To do all of the above, we need to create an entity for the metadata.

localFile.entity.ts

localFile.dto.ts

We also need to create a relationship between users and files.

user.entity.ts

We add the column above so that the entity of the user can hold the id of the avatar without joining all of the data of the avatar.

While we’re at it, we also need to create the basics of the :

localFiles.service.ts

The last step is to use the method in the :

users.service.ts

Retrieving the files

Now, the user can retrieve the id of their avatar.

To download the file with a given id, we can create a controller that streams the content.

The first step in achieving the above is extending the :

We also need to create a controller that uses the above method:

localFiles.controller.ts

We learn about the class and the header in the previous part of this series.

Doing the above allows the user to retrieve the file with a given id.

Filtering incoming files

We shouldn’t always trust the files our users upload. Fortunately, we can easily filter them with the and properties supported by multer.

localFiles.interceptor.ts

Let’s allow only files that include “image” in the mimetype and are smaller than 1MB.

If the file doesn’t meet the size requirements, NestJS throws 413 Payload Too Large. It could be a good idea to go beyond just checking the mimetype and using the file-type library.

Summary

In this article, we’ve covered the basics of managing files on our server through NestJS. We’ve learned how to store them on the server and return them to the user. When doing that, we’ve extended the built-in and implemented filtering.  There are still ways to extend the code from this article. Feel free to implement file deleting and use transactions as described in the 15th part of this series.

Thanks to learning about various ways of storing files, you are now free to compare the advantages and disadvantages and use an approach to suit your needs best.

Series Navigation<< API with NestJS #54. Storing files inside a PostgreSQL databaseAPI with NestJS #56. Authorization with roles and claims >>
Subscribe
Notify of
guest
6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ryan
2 years ago

Great tutorial! What about a tutorial on how to do Push Notifications when certain events happen in the API?

Ade
Ade
2 years ago
Reply to  Ryan

Nice,do Push Notifications when certain events happen in the API?

Dan
Dan
2 years ago

Fortunately, NestJS makes it very easy to store the files on the server. We need to pass additional arguments to the FileInterceptor.
users.service.ts users.controller.ts

Tommy
Tommy
1 year ago

Any chance to get an article about implementing file-type library in this article?

Last edited 1 year ago by Tommy
Dawid
Dawid
1 year ago

What kind of relation should I make when I want the entity to have multiple files? f.e – gallery of photos, etc.

Alexey
Alexey
10 months ago

thank you very much! the best tutorial, somehow you catch themes, which are not covered in other documentations and occur in real applications very often

Last edited 10 months ago by Alexey