We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Multipart Uploads

Let's work with some files already!

So you might already be familiar with simple JSON/HTML form POST requests. That works great for small structured data (small strings, integers, etc.), but what about large files?

We don't typically send massive files as single JSON payloads or forms. Instead, we use a different encoding format called multipart/form-data. In a nutshell, it's a way to send multiple pieces of data in a single request and is commonly used for file uploads. It's the "default" way to send files to a server from an HTML form.

Luckily, Bun has built-in support for parsing multipart/form-data requests. BunRequest extends the Request interface, which has a formData() method.

export async function handlerUploadThumbnail(cfg: ApiConfig, req: BunRequest) {
   // validate the request

  const formData = await req.formData();
  const file = formData.get("thumbnail");
  if (!(file instanceof File)) {
    throw new BadRequestError("Thumbnail file missing");
  }

   // read and save the image file data

Assignment

The handler for uploading thumbnails is currently a no-op. Let's get it working. We're going to keep it simple and store all image data in-memory.

  • Notice the type Thumbnail in src/api/thumbnails. There is a map of video IDs to thumbnail objects called videoThumbnails. This is where we're going to store the thumbnail data.

Complete the handlerUploadThumbnail function. It handles a multipart form upload of a thumbnail image and stores it in the videoThumbnails map:

  1. Authentication has already been taken care of for you, and the video's ID has been parsed from the URL path.

Bit shifting is a way to multiply by powers of 2. 10 << 20 is the same as 10 * 1024 * 1024, which is 10MB.

    • If the authenticated user is not the video owner, throw a UserForbiddenError error, which is available in src/api/errors
http://localhost:<port>/api/thumbnails/<videoID>

This will all work because the api/thumbnails/:videoID endpoint serves thumbnails from that global map.

Run and submit the CLI tests.

If you try to upload a different image, the browser might cache and show the old one. We'll deal with that later.