Let's create a URL expander with Node.JS
Tags: node, javascript, webdev, tutorial
Published: 2021-11-19 10:50:28

## Yep we are creating a URL expander not a URL shortener
![Node.JS URl expander preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2c7g6xn579txjrlg87zg.png) 
There are many tools like [bitly](https://bitly.com/), [shorturl](https://www.shorturl.at/) etc. through which we can convert our long and messy URL into a short and better looking URL. For example https://www.youtube.com/c/AngleBrace can become [shorturl.at/asIW4](https://shorturl.at/asIW4).
### But URL expander will do the opposite.
So we can get the original long URL from the short URL using it.
## But why?
Well some bad guy can take this virus download link eg. https://www.badsite.com/virus.exe and shorten it to https://shorturl.at/wDPZ5. And now just by seeing the short URL you won't be able to tell that this link downloads a virus. So sometimes to prevent viruses and inappropriate websites we can use a URL Expander.

## Lets start.
> You can also [see the video](https://youtu.be/l2La_PmzxQE) version on YouTube


So create a folder for the project. And open it up in the terminal. And then run `npm init -y` to create a new node js project. This will also create a **package.json**.
![Initializing a new Node.JS project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3qaygpyxfzf7w6zj5ry.png)
After that we need to install some packages. We will need **express** and **request**. So install them by running `npm i express request`
We will also install nodemon as our dev dependency. So we won't have to rerun the JavaScript file each time we make a change. So install it by running `npm i nodemon -D`
Now in the **package.json** we will delete the **test** script and create a **start** script.
```json
{
  "name": "url_expander",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "request": "^2.88.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}
```
Okay now lets create a **index.js** file and setup a basic NodeJS and Express project
```js
const express = require('express')
const app = express()

app.use(express.static('public'))

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html')
})

app.listen(3000, () => {
    console.log('Server is running on port 3000')
})
```
So now we can create a public folder. Inside that we will create our HTML, CSS and JS file. So our folder structure will look something like this
![NodeJS project folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgqjwe1etudcqe2vvgib.png)
Okay now in out HTML let's write some markup. We will have 3 main elements
1. A input where we can enter the short URL
2. Button that will send the request to expand URL
3. A element were we will show our expanded URL
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Node JS URL Expander</title>
</head>
<body>
    <div class="container">
        <div class="input-box">
            <input type="text" id="input" placeholder="Enter Short URL">
            <button id="expand-btn">expand</button>
        </div>
        <a href="" id="result"></a><!-- Expanded URl will be shown here -->
    </div>

    <script src="main.js"></script>
</body>
</html>
```
Now lets style it in our **style.css**
```css
*{
    margin: 0;
    padding: 0;
}
html, body{
    height: 100%;
}
body{
    background-color: rgb(239, 131, 84);
    display: flex;
    justify-content: center;
    align-items: center;
}

.container{
    width: 320px;
    padding: 3em;
    background-color: rgba(255, 255, 255, 0.3);
}
.input-box{
    height: 35px;
    display: flex;
}
input{
    flex-grow: 1;
}
button{
    background-color: rgb(233, 95, 35);
    color: white;
    text-transform: uppercase;
}
input, button{
    padding: 0 1em;
    display: block;
    border: none;
    outline: none;
}

#result{
    color: white;
    word-break: break-all;
    font-size: 1.2em;
    text-align: center;
    display: block;
    margin-top: 1em;
}
```
So now if we start our server by running `npm start` and go to `localhost:3000` we should see this page
![Nodejs project on localhost](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrl3rnldzfrbaa6nd0d9.png)
Great Now in our **main.js** lets make it so when we click on the button it sends a request to `/expand` and displays the response.
```js
const input = document.querySelector('#input')
const expandBtn = document.querySelector('#expand-btn')
const result = document.querySelector('#result')

expandBtn.addEventListener('click', () => {
    // Initally set the result to loading
    result.innerText = 'Loading ...'
    fetch(`/expand`)
        .then(res => res.text())
        .then(text => {
            // Display the result send from the server
            result.innerText = text
        })
        .catch(err => {
            console.log(err)
            result.innerText = 'Error'
        })
})
```

Now in our **index.js** lets create the `/expand` route.
```js
const express = require('express')
const app = express()

app.use(express.static('public'))

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html')
})

app.get('/expand', (req, res) => {
    res.send("hello")
})

app.listen(3000, () => {
    console.log('Server is running on port 3000')
})
```
 So now if we click on the button it should display **hello**
![NodeJS send fetch request from html](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7qvwajyzgzvg2194nrtw.png)
Okay now in out **main.js** when sending request to `/expand` lets also send our inputs value as a query parameter.
```js
const input = document.querySelector('#input')
const expandBtn = document.querySelector('#expand-btn')
const result = document.querySelector('#result')

expandBtn.addEventListener('click', () => {
    result.innerText = 'Loading ...'
    // passing the input value to the server as shortUrl query string
    fetch(`/expand?shortUrl=${input.value}`)
        .then(res => res.text())
        .then(text => {
            result.innerText = text
        })
        .catch(err => {
            console.log(err)
            result.innerText = 'Error'
        })
})
```
So now we can get the input value in our **index.js**
```js
app.get('/expand', (req, res) => {
    let shortUrl = req.query.shortUrl
    res.send("hello")
})
```
And now finally we can use the **request** package we installed earlier to get the original URL of our short URL
```js
const express = require('express')
const request = require('request')
const app = express()

app.use(express.static('public'))

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html')
})

app.get('/expand', (req, res) => {
    let shortUrl = req.query.shortUrl
    // If the shortUrl doesn't start with http, add add https:// in front of it
    // So eg. example.com becomes https://example.com
    if(!shortUrl.startsWith('http')) shortUrl = 'https://' + shortUrl
    request({
        url: shortUrl,
        method: "HEAD",
        followAllRedirects: true
    },
    (err, response, body) => {
        if (err) {
            console.log(err)
            res.send("Error")
        } else {
            // Sending back the full url
            res.send(response.request.href)
        }
    })
})

app.listen(3000, () => {
    console.log('Server is running on port 3000')
})
```
And now our project is complete. So enter a short URL like **shorturl.at/aoqyO** and click on expand and it should display the full URL
![Working Node JS URL expander](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6g419d3cc8l3rcatwfhn.png)

## You can the finished codes [here](https://github.com/0shuvo0/url-expander)


## Make sure you checkout my other articles and YouTube Channel
{% user 0shuvo0 %}
## Was it helpful? Support me on Patreon
[![Patreon Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vnw8g7vs5pok3jwgtgv.png)](https://www.patreon.com/0shuvo0)