Redirect a caller in Deno

Mayank C
Tech Tonic

--

Introduction

Redirection is a very common use case for web apps. Some typical redirection cases are:

  • Redirect to the login screen if authentication has expired
  • Redirect to a different landing page than published
  • Redirect from HTTP to HTTPS
  • Redirect from an unsupported old end point to a new one

The above are just a few examples. There are many more use cases for redirection.

The Node.js world generally uses express’s res.redirect(target) function to redirect a user to a target URL. In native Deno world, there is no such function. There is one provided in Oak (a popular framework), but nothing explicitly provided by the native code.

In this brief article, we’ll see how to do a native redirection in Deno.

Usage

We’ll use native HTTP server (hyper) for all the examples. For details about native server, check the article here.

The redirection is carried out with two pieces of information:

  • Status code: HTTP 3xx status codes are for redirections. The most used one is 302 Found. A complete list is here.
  • Target URL: The URL where the user is redirected to. The target URL goes to the caller in the location header (as per the specification).

A good documentation about general redirection can be seen here.

As per the specification, we need to set two things when redirecting:

  • HTTP status code
new Response(undefined, {status: Status.Found});
  • Location Header containing target URL
new Response(undefined, {status: Status.Found,
headers: {'location', URL}});

That’s all to do!

Note that the URL can be encoded if it contains characters not allowed in URI format. So, the final code could become:

new Response(undefined, {status: Status.Found,
headers: {'location', encodeURI(URL)}});

The same can be put inside a one-liner utility function:

const redirect = (resp:any, target:string, status:number=Status.Found) =>
resp(new Response(undefined, {status, headers: {'location': encodeURI(target)}}));

Examples

Now that we’ve seen the basic idea behind redirection, let’s write a small HTTP server that would redirect all the users that land on / to /login. The HTTP server is written using native code (i.e. without frameworks):

import { Status } from "https://deno.land/std/http/http_status.ts";
import { serve } from "https://deno.land/std/http/mod.ts";
const redirect = (target: string, status: number = Status.Found) =>
new Response(undefined, {
status,
headers: { "location": encodeURI(target) },
});
const serveText = (body: string) => new Response(body, { status: Status.OK });async function reqHandler(req: Request) {
return (new URL(req.url)).pathname === "/"
? redirect("/login")
: serveText("Welcome to login page");
}
serve(reqHandler, { port: 8000 });

The server code is very short. It checks the request path, and redirects all requests from / to /login.

Here are some sample runs using curl (-L option is used so that curl can follow the redirect) and browser:

bash >> curl http://localhost:5000 -vL
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 302 Found
< location: /login
< content-length: 0
< date: Fri, 25 Jun 2021 23:48:52 GMT
<
* Re-using existing connection! (#0) with host localhost
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /login HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/plain;charset=UTF-8
< content-length: 21
< date: Fri, 25 Jun 2021 23:48:52 GMT
<
* Connection #0 to host localhost left intact
Welcome to login page
* Closing connection 0

A direct request to /login is handled normally:

> curl http://localhost:5000/login -vL
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /login HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/plain;charset=UTF-8
< content-length: 21
< date: Fri, 25 Jun 2021 23:50:55 GMT
<
* Connection #0 to host localhost left intact
Welcome to login page
* Closing connection 0

The browser also follows the redirect correctly:

--

--