Build your very own URL shortener 🔗🚀
h
jajoosam (673)

Build a tiny URL shortener, using a remote database

Demo ⏯️ Code 👨‍💻

Setting up a URL shortener is a lot of work - either you have to pay, or spend hours setting up your own server.

This is a guide to making your own URL shortener with repl.it - using express, and a remote database - all on node.js

🛠️ Getting our environment running

First up, fork the https://repl.it/@jajoosam/tyni-starter repl, so that you have a running project. Next, create a new file - .env

A .env file can store secrets for you, that no one else will be able to see. This is where we want to store our token for accessing the remote database.

📁 Making our database

We're going to be using jsonstore.io for storing all our URLs.

Head over to jsonstore.io/get-token - and copy the token you see - this is the secret we want to store in our .env file.

Open up your .env file, and set KEY to your token, like this 👇

KEY=yourTokenGoesHere

Remember to keep no whitespace, or your token might not be recognized right!

When you open index.js you'll see that I've already initialized the database, and a small web server for you. Now let's get to making our API so we can shorten them URLs 🚀

👨‍💻 The API

There are two parts to our URL shortener:

  1. Storing the short link, corresponding to the long URL - in our database.
  2. Redirecting visitors from the short link to the long link

Both of these are super simple to implement, thanks to the express server we're using - we'll just be collecting get requests for both of the tasks.

For adding links to our database, we have a special endpoint - requests to it have two parts: the long URL, and the short path.

app.get('/shorten', (req, res) => {
	db.write(req.query.key, {"url": req.query.url});
	res.status(200);
});

Adding this to our code lets us correspond the short path (key) to the long url, and then we finally send a successful response.

For the second task, we'll just be collecting the short path (key) from a request, finding the corresponding URL in our database, and then redirecting our visitor ⬇️

app.get('/:key', (req, res) => {
	db.read(req.params.key + "/url").then( (url) => {
		res.redirect(url);
	});
}); 

That's prety much it - we have a fully functional URL shortener 🤯 - check it out for yourself, open a new URL which looks like this 🔗

https://tyni.jajoosam.repl.co/shorten?key=yay&url=https://dsh.re/50854

Now, going to http://tyni.jajoosam.repl.co/yay will be nice to see 👇

Of course, you'll be replacing tyni.jajoosam in those URLs with your own repl!

✨ The Frontend

Our URL shortener does work, but it's tedious, having to type out a huge URL before shortening it - we can make the whole process much simpler with a simple frontend.

I've already created this - and gone for a neat and minimal look using wing.css

You just have to add code to send visitors to the hompage in the static folder 🏠

app.get('/', (req, res) => {
	res.sendFile("static/index.html", {root: __dirname});;
});

If you browse through the static folder, you'll find a simple HTML file with a form, CSS to style our page, and most importantly, JS to send requests to our URL shortening API.

The HTML is quite straightforward, we're asking for the long URL, and optionally a short path.

Open up script.js and you'll see the shorten() function.

Here's what the JS file does (I've also annotated the code with comments) 👇

🔍 Getting the path(key) and the long url from the form.

📝 Possibly generating a random 5 character hash as our path (in case there's no path entered)

🔗 Sending a get request to our API, with our key and url as parameters

🖥️ Displaying the shortened URL on our page

🌐 Getting our custom domain

Sure, our links are shorter - but we still don't have them on our own domain, and the repl.co links can be pretty long 👀

Luckily for us, the folks at repl.it recently allowed custom domains to be used! That means this project could be something you actually use all the time 😄

Check out dotcomboom's guide on using custom domains, it should only take a few minutes. It also teaches you about getting free domains 💸

Be sure to put down any questions or improvements down in the comments 💬 - and here's all the code for you to go over again 🤖

https://repl.it/@jajoosam/tyni

You are viewing a single comment. View All
AgastyaSandhuja (66)

@jajoosam This is really cool! But I do have a few problems...
1) I get this error even though I followed the instructions:

    at fetch (/home/runner/tyni-url-shortener/node_modules/jsonstore.io/index.js:54:20)
    at FetchStream.<anonymous> (/home/runner/tyni-url-shortener/node_modules/fetch/lib/fetch.js:428:13)
    at FetchStream.emit (events.js:198:13)
    at FetchStream.<anonymous> (/home/runner/tyni-url-shortener/node_modules/fetch/lib/fetch.js:321:22)
    at IncomingMessage.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
(node:455) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:455) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:455) UnhandledPromiseRejectionWarning: Error: Token is incorrect, unable to read data.
    at fetch (/home/runner/tyni-url-shortener/node_modules/jsonstore.io/index.js:54:20)
    at FetchStream.<anonymous> (/home/runner/tyni-url-shortener/node_modules/fetch/lib/fetch.js:428:13)
    at FetchStream.emit (events.js:198:13)
    at FetchStream.<anonymous> (/home/runner/tyni-url-shortener/node_modules/fetch/lib/fetch.js:321:22)
    at IncomingMessage.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
(node:455) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

2) When I get my output, it still says l.4ty2.fun/link even though I edited the code

Could you please help?