File upload through fetch API in Deno

Mayank Choubey
Jun 9 · 3 min read

Introduction

Deno supports web standard’s fetch API to make HTTP requests (aka HTTP client). The fetch API is a pretty common & versatile API used in browsers. It can be used to easily make HTTP requests with built-in support for content types like:

  • Form data
  • URL encoded data
  • Readable stream
  • Blob

The fetch API supports web’s Request and Response interfaces. A request object is created with all the data and given to fetch API. The fetch API makes the HTTP request, and returns a response object to the caller. A great documentation of fetch API is available here.

One of the common use case of the fetch API is to upload files. The Request object supports file upload via Blob or web’s ReadableStream. Deno supports ReadableStream, but this isn’t commonly used in Deno’s world. Deno code commonly uses Reader instead of ReadableStream. There is a need for an easy way to convert Deno’s Reader into a ReadableStream that can be given to the Request object of the fetch API.

In this article, we’ll go over how to do file uploads through fetch API in Deno. We’ll see how to easily convert Reader into ReadableStream.

Usage

Deno’s standard library’s io modules comes with a utility function readableStreamFromReader that can easily convert a Deno Reader into a ReadableStream.

As readableStreamFromReader is part of the standard library, it needs to be imported:

The function readableStreamFromReader takes two inputs:

  • Reader: This is the Reader that needs to be converted to web’s ReadableStream. This is a mandatory input. (aka Deno.Reader)
  • Options: These are some additional options like autoClose (close the Reader when done), chunkSize (default is 16K). These are not commonly used.

The function readableStreamFromReader produces a single output that is the ReadableStream object. The ReadableStream object contains a stream of bytes (Uint8Array).

The basic usage might be suitable for most of the use cases. The basic usage involves the following steps:

  • Create a Deno Reader (like file, connection, etc.)
  • Convert it to ReadableStream and set it in Request object
  • Use Request object in the fetch API call

The Reader can be already available like a socket connection, or can be created like by opening a file. To get more info on Deno Reader, check this story here.

While the Reader can be easily converted to ReadableStream using readableStreamFromReader, setting of required HTTP headers need to be done by the caller. Two of the useful headers are:

  • Content type: This needs to be set explicitly
  • Content length: This also needs to be set explicitly

Content length should have been set by the fetch implementation, but Deno’s fetch doesn’t set content length. If there is a way to have fetch set it, let us know and we’ll update the example.

Local file upload

We’ll now go over the use-case and see how file upload can be easily done by converting Deno’s Reader to web’s ReadableStream. This is the case where an app wants to upload a local file. Possibly monitoring a directory for new files, and uploads them to some server as soon as new ones are found.

The local file upload is done in the following steps:

  • Open the file and get a Reader
  • Convert Reader to ReadableStream
  • Set headers (content-type and content-length)
  • Make the fetch API call

Note that Deno.stat function is used to get the size of the file. The size must be sent in content-length header explicitly.

Deno World

The world of Deno