Edit

How to Use Redis with Deno

Redis is an in-memory data store you can use for caching, as a message broker, or for streaming data.

View source here.

Here we’re going to set up Redis to cache data from an API call to speed up any subsequent requests for that data. We’re going to:

  • Set up a Redis client to save data from every API call in memory
  • Set up a Deno server so we can easily request certain data
  • Call the Github API within the server handler to get the data on first request
  • Serve data from Redis on every subsequent request

We can do this within a single file, main.ts.

Connecting to a Redis client

We need two modules. The first is the Deno server. We’ll use this to get the information from the user to query our API. The second is Redis. We can grab the node package for Redis using the npm: modifier:

import { Server } from "https://deno.land/std@0.181.0/http/server.ts";
import { createClient } from "npm:redis@^4.5";

We create a Redis client using createClient and connect to our local Redis server:

// make a connection to the local instance of redis
const client = createClient({
  url: "redis://localhost:6379",
});

await client.connect();

You can also set host, user, password, and port individually in this configuration object.

Setting up the server

Our server is going to act as a wrapper around the Github API. A client can call our server with a Github username in the URL pathname, such as http://localhost:3000/{username}.

Parsing out the pathname and calling the Github API will take place inside a handler function in our server. We strip the leading slash so we are left with a variable we can pass to the Github API as a username. We’ll then pass the response back to the user.

const server = new Server({
  handler: async (req) => {
    const { pathname } = new URL(req.url);
    // strip the leading slash
    const username = pathname.substring(1);
    const resp = await fetch(`https://api.github.com/users/${username}`);
    const user = await resp.json();
    return new Response(JSON.stringify(user), {
        headers: {
          "content-type": "application/json",
        },
      });
    }
  },

  port: 3000,
});

server.listenAndServe();

We’ll run this with:

deno run --allow-net main.ts

If we then go to http://localhost:3000/ry in Postman, we’ll get the Github response:

uncached-redis-body.png

Let’s cache this response using Redis.

Checking the cache

Once we have our response from the Github API, we can cache this within Redis using client.set, with our username as the key and the user object as the value:

await client.set(username, JSON.stringify(user));

Next time we request the same username, we can use client.get to get the cached user:

const cached_user = await client.get(username);

This returns null if the key doesn’t exist. So we can use it in some flow control. When we get the username, we’ll initially check whether we already have that user in the cache. If we do we’ll serve the cached result. If not, we’ll call the Github API to get the user, cache it, the serve the API result. In both cases, we’ll add a custom header to show which version we’re serving:

const server = new Server({
  handler: async (req) => {
    const { pathname } = new URL(req.url);
    // strip the leading slash
    const username = pathname.substring(1);
    const cached_user = await client.get(username);
    if (cached_user) {
      return new Response(cached_user, {
        headers: {
          "content-type": "application/json",
          "is-cached": "true",
        },
      });
    } else {
      const resp = await fetch(`https://api.github.com/users/${username}`);
      const user = await resp.json();
      await client.set(username, JSON.stringify(user));
      return new Response(JSON.stringify(user), {
        headers: {
          "content-type": "application/json",
          "is-cached": "false",
        },
      });
    }
  },

  port: 3000,
});

server.listenAndServe();

Running this first time gives us the same response as above, and we’ll see the is-cached header set to false:

uncached-redis-header.png

But call with the same username again, and we get the cached result. The body is identical:

cached-redis-body.png

But the header shows we have the cache:

cached-redis-header.png

We can also see that the response was ~200ms quicker!

You can check out the Redis documentation here and the Redis node package here.