DEV Community

Cover image for Build automatic URL shortener with react and Emly
Emmanuel Etukudo
Emmanuel Etukudo

Posted on

Build automatic URL shortener with react and Emly

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.

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

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

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, 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.

npx create-react-app emly-app
Enter fullscreen mode Exit fullscreen mode

Next, run the code below to test run your app.

cd emly-app &&
npm start
Enter fullscreen mode Exit fullscreen mode

Your app should look similar to the screenshot below.

emly.cc

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


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;
Enter fullscreen mode Exit fullscreen mode

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.

import './App.css';
import ResizableTextarea from './components/ResizeableTextbox';
function App() {
  return (
    <div className="App">
      <header className="App-header">
      <ResizableTextarea/>
      </header>
    </div>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

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.

.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;
}
Enter fullscreen mode Exit fullscreen mode

Now, run the app with the command below.

npm run start
Enter fullscreen mode Exit fullscreen mode

Your app should look similar to the screenshot below.

emly.cc

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.

mkdir emly-server &&
npm init -y
Enter fullscreen mode Exit fullscreen mode

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

npm i emly-nodejs body-parser cors dotenv express nodemon
Enter fullscreen mode Exit fullscreen mode

Now, create a new file index.js, and copy-past the code below.

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}`);
})
Enter fullscreen mode Exit fullscreen mode

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

KEY=your_api_key_goes_here
Enter fullscreen mode Exit fullscreen mode

Next, run the code below to start the server.

npm run serve
Enter fullscreen mode Exit fullscreen mode

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

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’s URL shortener has a detailed API to get you started within few minutes.

Discussion (0)