I built an URL shortener with Cloudflare KV

vikashrathee

Vikash Rathee

Posted on December 9, 2023

I built an URL shortener with Cloudflare KV

I am building an open source, highly scalable, and low-cost URL shortener with Cloudflare KV

URL shortening software

By low-cost I mean, just $5 per month on Cloudflare worker and a free plan for basic requirement -

Idea

At DaySchedule, we had many customer upvoted for a URL shortener feature with auto-expirable links to book an appointment instead sharing their original URL.

So, I decided to try Cloudflare for this project -

By leveraging Cloudflare KV's capabilities, the goal was to develop a solution that offered not only URL shortening but also customization options, analytics, and scalability, all while maintaining a significantly lower cost compared to our established services on AWS.

Features

API

I used hono.dev by @yusukebe for API routing, and it's blazing fast and offers Cloudflare pages template to build Edge projects quickly.

Here is an example of server.ts from their docs -

import { Hono } from 'hono'
const app = new Hono()

app.get('/', (c) => c.text('Hono!'))

export default app
Enter fullscreen mode Exit fullscreen mode

Controller

The /links API is all I need to create, update and manage the short links.

const links = new Hono<{ Bindings: Bindings }>();

links.post(
  '/',
  validator('json', (value, c) => {
    const parsed = linkSchema.safeParse(value);
    if (!parsed.success) {
      return c.json(parsed, 400);
    }
    return parsed.data as ShortLink;
  }),
  async (ctx) => {
    const data = ctx.req.valid('json');
    // Set expire_at if given, or fallback to 1 month expiry
    const expireAt = data.expire_at
      ? dayjs(data.expire_at).unix()
      : dayjs().add(1, 'month').unix();
    if (expireAt <= dayjs().unix()) {
      return ctx.json(
        { message: 'The expire_at must be greater then current date time' },
        400
      );
    }

    let key = data.key || nanoid(7);
    let exists = await ctx.env.SHORTLINKS.get(key);
    while (exists) {
      key = nanoid(7);
      exists = await ctx.env.SHORTLINKS.get(key);
    }
    await ctx.env.SHORTLINKS.put(key, JSON.stringify(data), {
      expiration: expireAt,
    });
    return ctx.json(
      { ...data, key: key, short_url: `https://idm.in/${key}` },
      200
    );
  }
);
Enter fullscreen mode Exit fullscreen mode

Code explanations -

This code is POST request to create short links. Here's a breakdown of the code to explain what all I am doing:

  1. const links = new Hono<{ Bindings: Bindings }>(): It creates an instance of the Hono object.

  2. Validation with zod - The validator('json', (value, c) => {...}): function is used as a middleware for validating the incoming JSON payload defined in linkSchema.

  3. Set expiration: Checks if an expiry date is provided in the payload. If not, it sets an expiry date one month from the current date and time.

  4. Generates a unique key for the link using nanoid(7) or uses the provided key from the payload if available.

  5. Stores the link data (converted to a JSON string) in the Cloudflare KV (SHORTLINKS) with an expiration time based on the calculated expiry date.

Demo

The demo is available on IDM, it's free to use and open-sourced on Github to build your own custom URL shortener.

Short your links

You can clone the repo to deploy on your Cloudflare account.

Star the repository on Github to show your support :-)

💖 💪 🙅 🚩
vikashrathee
Vikash Rathee

Posted on December 9, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

I built an URL shortener with Cloudflare KV
urlshortener I built an URL shortener with Cloudflare KV

December 9, 2023