Easy link shortener in JavaScript, Cloudflare Workers and Telegram Bot

What if you need to quickly create a short link? Of course - use a link shortener. What if you also make this link readable? Still using your own domain? And it would be better to do it without additional servers. It seems that there is an answer.






Background

The idea of ​​an "easy link shortener" came to me when I was looking for a redirect option using a domain for one of the rooms in the newfangled Clubhouse social network . The essence of the room call forwarding idea was to restart a room with the same name, but always online . It was necessary to solve the problem of constantly changing the address of the room by parking such a link to the sub-domain.





The decision came up by itself, since the site was pre-planted on Cloudflare. Initially, I used the “Page Rules” function, which allows you to set, among other things, redirect rules, but soon the idea came to make this redirection more flexible and changeable without the need to go into the service settings. Of course, Telegram Bot became such a solution.





Formulation of the problem

In order to accomplish our plan, several problems need to be solved:





  • How to redirect from a specific sub-domain?





  • Where to save links by key (abbreviation) - value (forwarding address)?





  • How to create such abbreviations?





As you may have guessed, the answers to these questions are in the very title of the article. Therefore, I propose to proceed to the practical part.





Preconditions

For a more detailed description, I will note the basic conditions necessary for the implementation of our project:





  • Domain connected to Cloudflare;





  • General knowledge of JavaScript;





  • Telegram bot created;





  • Documentation for Cloudflare Workers and Telegram Bot API .





How to fulfill the necessary preconditions is not covered in this article. The solution to these problems remains with the reader.





Training

, , — « ?». :





1. – Cloudflare KV.





Cloudflare KV — Worker' « - ». , Cloudflare.





: Workers KV, , .





Cloudflare KV page
Cloudflare KV

. , . , , .





Inside our vault

2. Worker .





«Create worker», Worker («Save and Deploy») .





This is how the page of the new Worker looks like
Worker'

«Settings» Telegram , .





Worker settings
Worker'

3. -





, url.mydomain.com



, «-» -.





Workers page for our domain
Workers

, «Workers» «Route» -.





Adding a new redirect

, , (path - ) .



.





, DNS DNS .





New DNS record that will contain the link shortener
DNS

! .





. , Cloudlfare. Worker. «Quick edit» .





Code editor

:













(URL path) . 404.





addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

/**
 * Respond to the request
 * @param {Request} request
 */
async function handleRequest(request) {
  const requestUrl = new URL(request.url);
  const path = requestUrl.pathname.substring(1); //   "/"
  return await redirect(path)
}

/**
 * Make redirect
 * @param {string} shortName
 */
async function redirect(shortName) {
  //        
  const url = await db.get(shortName);
  if (url) {
    //   
    return Response.redirect(url)
  }
  //    
  return new Response(null, {status: 404})
}

      
      



, , :





There is a contact!
!

. . Telegram URL. , Telegram User ID . . webhook'.





addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

const ADMIN = 11111111; //   Telegram User ID

/**
 * Respond to the request
 * @param {Request} request
 */
async function handleRequest(request) {
  const requestUrl = new URL(request.url);
  const path = requestUrl.pathname.substring(1);
  //        
  if (path == BOT_TOKEN) {
    return await bot(await request.json())
  }

  return await redirect(path)
}

/**
 * Make redirect
 * @param {string} shortName
 */
async function redirect(shortName) {
  const url = await db.get(shortName);
  if (url) {
    return Response.redirect(url)
  }
  return new Response(null, {status: 404})
}

/**
 * Create new shorten URL
 * @param {Object} update
 */
async function bot(update) {
  //     
  if (update.message.from.id != ADMIN) {
    return new Response("OK", {status: 200})
  }
  //    "shortname url"
  const [shortName, url] = update.message.text.split(" ");
  //    
  await db.put(shortName, url);
  const response = {
    //         
    "method": "sendMessage",
    //        -  
    "text": ` ${url}     url.mydomain.com/${shortName}`,
    //   ,     ADMIN (  ), 
    //  update.message.chat.id      
    //     
    "chat_id": update.message.from.id
  }

  return new Response(
    JSON.stringify(response), 
    {
      status: 200,
      headers: new Headers({"Content-Type": "application/json"})
    }
  )
}

      
      



, , :





Looks workable

( ):





Working

– Telegram Bot Webhook. , :





https://api.telegram.org/bot[BOT_TOKEN]/setWebhook?url=url.domain.com/[BOT_TOKEN]







Telegram API :





{"ok":true,"result":true,"description":"Webhook was set"}
      
      



. , , .



« !»





« » .





, Cloudflare Worker'. , :





  • 1000 ( );





  • read from the database up to 100,000 times a day (maximum number of visits);





  • the script itself can be run up to 100,000 times a day (the number of messages to the bot and visits to shortened links);





  • the script should run no more than 1000 times per minute.





These restrictions should be enough for personal use, share your opinion on this in the comments.








All Articles