API with NestJS #118. Uploading and streaming videos

NestJS

This entry is part 118 of 168 in the API with NestJS

Nowadays, video streaming is one of the main ways of consuming and sharing content. In this article, we explore the fundamental concepts of building a REST API for uploading videos to the server and streaming them using NestJS and Prisma.

Check out this repository if you want to see the full code from this article.

Uploading videos

NestJS makes it very straightforward to store the files on the server with the .

videos.controller.ts

Whenever we make a valid POST request to the API, NestJS stores the uploaded videos in the directory.

In one of the previous parts of this series, we created a custom interceptor that allows us to avoid repeating some parts of our configuration whenever we need more than one endpoint that accepts files. It also allows us to use environment variables to determine where to store files on the server.

videos.controller.ts

Above, we are using the mixin pattern. If you want to know more, check out API with NestJS #57. Composing classes with the mixin pattern

To use our custom interceptor, we need to add to our environment variables.

app.module.ts

.env

Thanks to all of the above, we can now take advantage of our custom interceptor in the videos controller.

videos.controller.ts

Storing the information in the database

Once we have the file saved on our server, we need to store the appropriate information in our database, such as the path to the file. To do that, let’s create a new table.

videoSchema.prisma

We also need to create the appropriate SQL migration.

If you want to know more about migrations with Prisma, go to API with NestJS #115. Database migrations with Prisma

Thanks to defining the new table with Prisma, we can now store the information about a particular video in the database.

videos.service.ts

Streaming videos

The most straightforward way to stream files is to create a readable stream using the path to our file and the class.

videos.service.ts

If you want to know more about the class, check the following articles:
API with NestJS #54. Storing files inside a PostgreSQL database
API with NestJS #55. Uploading files to the server

videos.controller.ts

In our frontend application, we need to use the tag and provide the URL of a video with a particular id.

Improving the user experience

While the above approach works, it is far from ideal. Its main drawback is that it does not allow the user to forward a video instead of watching it from start to finish. The first step in improving this is sending the response header.

By sending the header to the browser, we indicate that we support serving parts of a file. A good example is when the user tries to start the video in the middle.

The browser then sends us the header that indicates what fragment of our file it needs. It supports specifying multiple different portions of a file, such as:

The numbers specify the ranges using bytes. While we could write the logic of parsing the header ourselves, there is a popular library that can do that for us.

To calculate the precise range of the file we need to serve, the library needs the maximum size of the resource. To get this information, we use the function built into Node.js.

videos.service.ts

The library returns or when something went wrong with parsing. We can use that to throw the error. In our streaming functionality we only support a single range of video, so we want to throw an error when someone requests more than one range through the header.

The last piece of information we need to send to the browser is the header. It tells the browser what fragment of the video we are sending. To create this header, we need the information parsed by the library.

videos.service.ts

Thanks to creating all of the above methods, we can now create a function that uses all of them.

videos.service.ts

We need to respond with the status code to indicate that the response contains the requested data ranges.

videos.controller.ts

Summary

Thanks to the above approach, we increased the user experience of our video streaming. Whenever the user clicks on the video player, the browser sends a new GET request to our API with a different header. We then use this information to serve a stream of the requested fragment of the video. This allows the user to fast-forward or rewind the recording, which is an essential feature of any video streaming service.

Series Navigation<< API with NestJS #117. CORS – Cross-Origin Resource SharingAPI with NestJS #119. Type-safe SQL queries with Kysely and PostgreSQL >>
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Andromadus Naruto
1 year ago

This was a good read. I also learnt a lot about streaming videos over a REST API. Thanks @Marcin