Build automatic URL shortener with react and Emly
Tags: react, javascript, webdev, reactnative
Published: 2021-09-22 23:59:25

Automatic link shortening is increasingly getting popular. Top tech companies (eg: Twitter and LinkedIn) are leveraging automatic link shortening to reduce the length of horrible-looking URLs. Twitter uses `T.co` behind the senses to shorten URLs posted on the micro-blogging platform. LinkedIn also uses the same technique to shorten links posted on the platform.

In this tutorial, we'll explore how to implement automatic link shortening in react using [Emly.cc](http://emly.cc).


To follow along with this React tutorial, you should have:


- Familiarity with CSS, HTML, and Javascript ES6
- Node.js installed on your system
- A web browser installed in your system, i.e., Chrome
- A code editor installed on your development machine, i.e., VS Code
- A basic understanding of React


## Setting up an Emly account

Visit http://emly.cc/register to create a new account.

![emly.cc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mg4qf9vbr708dt1w4o5w.png)

Next, obtain your API key from your dashboard. Scroll down to the footer, click on the developer, select link, and click on Get your API key. See screenshot below:

![emly.cc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkf9nblj7v0ovn3v3o8e.png)

With your API key in place, let’s proceed to build our project in the next section.

## Building the frontend 

Before we begin, let's initialize a new React app, install the [emly-nodejs SDK](https://www.npmjs.com/package/emly-nodejs), and set up a backend server for the project. Navigate to your work directory, and run the code below in your terminal for `mac` users or command prompt for `windows` users to initialize a new react project.

```bash
npx create-react-app emly-app
```
Next, run the code below to test run your app.

```bash
cd emly-app &&
npm start
```
Your app should look similar to the screenshot below.

![emly.cc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4px0pa520z63bj45zx3.png)

Next, create a new folder `components`, navigate to it and create a file `ResizeableTextbox.js` and copy-paste the code below.  

```react

import React from 'react';
import axios from 'axios';
class ResizableTextarea extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            post: '',
            rows: 5,
            minRows: 5,
            maxRows: 20,
            showPost: false,
            newPost: null,
        };
        this.handelSubmit = this.handelSubmit.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.getUrl = this.getUrl.bind(this);
        this.replaceUrl =  this.replaceUrl.bind(this);
    }

    replaceUrl = (post) => {
        if(!post) return;
        var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
        return post.replace(urlRegex, function(url) {
            var link = url;
            if (!link.match('^https?:\/\/') ) {
                link = 'http://' + link;
            }
        return '<a href="' + link + '" target="_blank" rel="noopener noreferrer">' + url + '</a>'
        })
    }
    getUrl = (post) => {
        var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
        return post.match(urlRegex);
    }
    handleChange = (event) => {
        const textareaLineHeight = 24;
        const { minRows, maxRows } = this.state;
        const previousRows = event.target.rows;
        event.target.rows = minRows; // reset number of rows in textarea 
        const currentRows = ~~(event.target.scrollHeight / textareaLineHeight);
        if (currentRows === previousRows) {
            event.target.rows = currentRows;
        }
        if (currentRows >= maxRows) {
            event.target.rows = maxRows;
            event.target.scrollTop = event.target.scrollHeight;
        }
        this.setState({
            post: event.target.value,
            rows: currentRows < maxRows ? currentRows : maxRows,
        });
    };
    handelSubmit = (e) => {
        e.preventDefault();
        let post = this.state.post;
        let urls = this.getUrl(post);
        var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
        var self = this;

        axios.post('http://localhost:9000/create',
            { url: urls[0] })
            .then(function (res) {
                if (res.data) {
                    const url = res.data.data.short_url;
                    const newPost =   post.replace(urlRegex, res.data.data.short_url);
                  self.setState({
                    showPost: true, 
                    newPost: newPost
                });
                }
            })
    }
    render() {
        return (
            <div className="col-md-8">
                {!this.state.showPost && <form onSubmit={this.handelSubmit}>
                    <label className="form-label">Creat a Post</label>
                    <textarea
                        rows={this.state.rows}
                        value={this.state.post}
                        placeholder={'Enter your text here...'}
                        className={'textarea'}
                        onChange={this.handleChange}
                    />
                    <button type="submit" className="btn btn-warning">Publish</button>
                </form>}
                {this.state.showPost &&
                    <div className="card" style={{border: '1px', margin: "20px"}}>
                        <div className="card-body">
                            <p className="card-text m-4">
                            <span dangerouslySetInnerHTML={{__html: this.replaceUrl(this.state.newPost)}} />
                            </p>
                        </div>
                    </div>
                }
            </div>
        );
    }
}
export default ResizableTextarea;
```

From the code snippet above,  when a user submits the form, the `handelSubmit` function is called, we use the regular expression `urlRegex` to search for URL from the post, and pass it to our backend server which in turn communicate to emly.cc’s API to get the link shortened.  The `replaceUrl` function searches the post once more, this time to convert the shortened URL to a clickable hyperlink.

Next, update the code in `App.js`  with the code below.

```react
import './App.css';
import ResizableTextarea from './components/ResizeableTextbox';
function App() {
  return (
    <div className="App">
      <header className="App-header">
      <ResizableTextarea/>
      </header>
    </div>
  );
}
export default App;
```
Next, run the code below in the terminal for `mac` or command prompt for `windows` users to start your app. 

Lastly, update the App.css with the code below.

```css
.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: #ffffff;
}

.App-link {
  color: #61dafb;
}

.textarea {
  box-sizing: border-box;
  border: none;
  border-radius: 3px;
  resize: none;
  font-size: 20px;
  line-height: 24px;
  overflow: auto;
  height: auto;
  color: #282c34;
  padding: 8px;
  width: 100%;
  box-shadow: 0px 4px 10px -8px black;
}
.textarea::-moz-placeholder {
  color: gainsboro;
}
.textarea:-ms-input-placeholder {
  color: gainsboro;
}
.textarea::placeholder {
  color: gainsboro;
}
.textarea:focus {
  outline: none;
}
```
Now, run the app with the command below.

```bash
npm run start
```

Your app should look similar to the screenshot below.

![emly.cc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32fueos2d7fsplu6fmc3.png)


## Building the back-end server

Now that you have completed the frontend on the project, let’s proceed to build a server that will handle all our backend requests. 

Navigate into your work directory and follow the instructions below to initialize a new `Nodjs` project. 

```bash
mkdir emly-server &&
npm init -y
```

On initialization complete, run the code below to install the `emly-nodejs` SDK and other dependencies required in this section.

```bash
npm i emly-nodejs body-parser cors dotenv express nodemon
```
Now, create a new file index.js, and copy-past the code below.

```react
require('dotenv').config();
const express = require('express');
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');
const port = 9000;
const emly = require('emly-nodejs')(process.ev.KEY);

//Body-Parser
app.use(express.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: "50mb", extended: true }));
app.use(bodyParser.json());
//handel cors
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
});
app.use(cors({
    origin: '*',
    methods: ['GET','POST','DELETE','UPDATE','PUT','PATCH']
}));

app.get('/links', (req, res) => {
   emly.link.list()
   .then(function(body){
       res.send(body);
   })
   .catch(function(error){
       res.send(error);
   })
})
app.post('/create', (req, res) => {
    const {url} = req.body;
    emly.link.create({
        url: url,
      })
        .then(function(error, body) {
            res.send(error);
            res.send(body);
    });
 })

app.listen(port, () => {
    console.log(`Server is listening at ${port}`);
})
```

Note: endeavor to create a .env file and add your API key. See the example below.

```bash
KEY=your_api_key_goes_here
```
Next, run the code below to start the server.

```bash
npm run serve
```
With your backend and front-end server running, add text with a long URL to the text box and click publish.  After the article is published, your app should look similar to the screenshot below.

![emly.cc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79ff9kd1pmdz7apzviza.png)


## Conclusion

Whether you are looking to add automatic `URL` shortening to your existing react app, or you want to get detailed analytics of all the links shared on your mobile/web app, [emly.cc](https://emly.cc/developers/links)’s URL shortener has a detailed `API` to get you started within few minutes.