DEV Community

Cover image for How to Build a Link-shortening App with React and Bitly API.
Frank Otabil Amissah
Frank Otabil Amissah

Posted on • Updated on

How to Build a Link-shortening App with React and Bitly API.

Link shortening is a way to reduce an excessively long URL into a short URL using link management software.

In this tutorial, I teach how to make a link shortener using the Bitly API and React.

Here's a demo of the app.

demo of link shortening app

Bitly is a URL-shortening service and a link management platform.
-Bitly

React is a javascript front-end library for making user interfaces.

Note: This tutorial uses node v18, and react v18.

let's dive in.

Bootstrapping a new react app.

Run the code below in your terminal to start a new react project:

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

The command automatically creates a folder with the name specified for the project.

After react app is set up successfully, navigate into your react project directory by running:

cd app_name
Enter fullscreen mode Exit fullscreen mode

In your project directory, install React-copy-to-clipboard by running the following command in your terminal:

npm install react-copy-to-clipboard
Enter fullscreen mode Exit fullscreen mode

Now, run the following command to view your application on localhost:3000.

npm run start
Enter fullscreen mode Exit fullscreen mode

Restructuring project directory

Open your text editor and structure your ./src directory to look like so,

|--/src
|  |--/icons
|  |--Home.css
|  |--Home.js
|  |--index.css
|  |--index.js
Enter fullscreen mode Exit fullscreen mode

You may delete App.test.js, setupTest.js, and reportWebVitals.js from your directory as you'll not need them in this tutorial.

icons folder will contain icons you'll use in the app.

Making the UI component.

Add the following code to your /src/Home.js file:

import { useState } from "react";
import { CopyToClipboard } from "react-copy-to-clipboard";
import "./Home.css";
import send from './icons/send.png';
import copyicon from './icons/copy.png';
import copiedicon from './icons/copied.png';

function Home() {
  const [longURL, setLongUrl] = useState("");
  const [shortLink, setShortLink] = useState({});
  const [active, setActive] = useState(false);
  const [copy, setCopy] = useState(false);

  function handleChange(e) {
    setLongUrl(e.target.value);
  }

  async function handleSubmit(e) {
    e.preventDefault();
    await fetch("https://api-ssl.bitly.com/v4/shorten", {
      method: "POST",
      mode: "cors",
      headers: {
        Authorization: `Bearer ${process.env.REACT_APP_BITLY_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        long_url: longURL,
        domain: "bit.ly",
        group_guid: `${process.env.REACT_APP_GUID}`,
      }),
    })
      .then((res) => res.json())
      .then((data) => {
        const new_link = data.link.replace("https://", "");
        fetch(
          `https://api-ssl.bitly.com/v4/bitlinks/${new_link}/qr?image_format=png`,
          {
            mode: "cors",
            headers: {
              Authorization: `Bearer ${process.env.REACT_APP_BITLY_TOKEN}`,
            },
          }
        )
          .then((response) => response.json())
          .then((result) => {
            setShortLink(result);
            setActive(true);
          });
      });
    setLongUrl("");
  }

  return (
    <div className="App">
      <h2>A Simple Bitly Link Shortener</h2>
      <div>
        <form method="post" action="" onSubmit={handleSubmit}>
          <input
            name="long_url"
            type="text"
            value={longURL}
            placeholder="Paste your url"
            onChange={handleChange}
          />
          <button type="submit"><img src={send} alt="send icon" id="send_icon"/></button>
        </form>

      </div>

      {/* show on success... */}

      {active ? (
        <div className="show_links">
          <img src={shortLink.qr_code} alt="Qr code" className="qr_img"/>
          <div>
            <h3>Here's your short link...</h3>
            <span>
              <p>{shortLink.link}</p>
              <CopyToClipboard onCopy={()=>{
                setCopy(true);
              }} text={shortLink.link}>{ !copy ? <img src={copyicon} alt="copy icon" width="17px" height="17px"/> : <img src={copiedicon} alt="copy icon" width="17px" height="17px"/>  }</CopyToClipboard>

            </span>
          </div>
        </div>
      ) : (
        ""
      )}
    </div>
  );
}

export default Home;

Enter fullscreen mode Exit fullscreen mode

The async handleSubmit function is called when we click the submit button. You'll notice that it contains two fetch methods, one contained in the other. The first fetch method submits the URL to bitly and passes the bit.ly link received in the response object to the second fetch method which is then used to request the QR code.

The handleChange function is called to update the input field as we type.

Now, go to /src/index.js and override its content with the following code.

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import Home from "./Home";
import reportWebVitals from "./reportWebVitals";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Home />
  </React.StrictMode>
);

reportWebVitals(console.log))
reportWebVitals();

Enter fullscreen mode Exit fullscreen mode

The code blocks above imports and renders the home component in the root node.

Adding project icons.

Download the icons from Mediafire, unzip and paste its content in /src/icons.

Styling the component.

Note: In this tutorial, we'll not focus on CSS so I prepared some CSS to add to the project.

In your /src/Home.css file add the following code:

* {
  margin:0;
}
.App {
width:100%;
height:100vh! important;
text-align:center;
background-color:rgb(207, 207, 207);
display:flex;
align-items:center;
justify-content:center;
flex-direction:column;
}

h2{
  padding:0 0 20px;
  font-size:2rem;
}

input[type=text] {
  font-size: 1.2rem;
  width: 300px;
  height: 100%;
  border-radius: 8px 0 0 8px;
 background-color: rgb(233, 233, 233);
 text-align: center;
 padding: 10px 20px;
 border: none;
}
input[type=text]:focus {
  outline: none;
  border: none;
}
button{
  font-size:1.2rem;
  box-sizing: border-box;
  height:100%;
  padding:10px 25px;
  border:none;
  border-radius:0 8px 8px 0;
}
button:hover{
  background-color: rgb(39, 137, 179);
}
#send_icon{
  width:21px; 
  height:1.2rem;
  vertical-align: middle;
}
.show_links {
  padding: 10px;
  margin-top: 20px;
  display: flex;
  flex-direction: row;
  column-gap: 20px;
  align-items: flex-end;
  background-color: rgb(233, 233, 233);
  width:400px;
  height:100px;
  animation-name: fadeIn;
  animation-duration: 3s;
}
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.qr_img {
  width: 100px;
  height: inherit;
  background-color: black;
  color: white;
}
.show_links  p {
  width: 200px;
  padding: 10px 15px;
  text-align: left;
  font-weight: 500;
  border: 1.5px solid rgb(179, 179, 179);
  border-radius: 8px;
}
 span {
  display: flex;
  flex-direction:row;
  padding: 10px 0;
  column-gap: 15px;
  justify-content: center;
  align-items: center;
}
h3 {
  text-align: left;
  margin-bottom: 10px;
  color: rgb(39, 137, 179);
}

/*for smaller devices */
@media (max-width:700px){
  h2{
    padding:0 0 20px;
    font-size:1.3rem;
  }
  .show_links {
    padding: 15px;
    margin-top: 20px;
    display: block;
    width:200px;
    height:300px;
  }
  .qr_img {
    width: 200px;
    height: 200px;
    margin: auto;
  }
  h3 {
    margin: 10px 0;
    color: rgb(39, 137, 179);
    font-size: 1.05rem;
  }
  input[type=text] {
    font-size: 1rem;
    width: 170px;
    height: 100%;
    border-radius: 8px 0 0 8px;
   background-color: rgb(233, 233, 233);
   text-align: center;
   padding: 10px 20px;
   border: none;
  }
  button {
    font-size: 1rem;
  }
  #send_icon {
    width: 1.05rem;
    height: 1rem;
    vertical-align: middle;
  }
  .show_links  p {
    width: 170px;
    font-size:0.9rem;
  }
  span {
    column-gap: 10px;
  }
}

Enter fullscreen mode Exit fullscreen mode

Override your ./src/index.css file with the following code:

body {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  background-color: rgb(233, 233, 233);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

Enter fullscreen mode Exit fullscreen mode

Setting up authentication token.

Now, go to Bitly.com and create an account if you don't already have one.

Login into your dashboard and navigate to Settings >> API

Bitly settings dashboard

Enter your Password and generate your API token.

In your root directory, create a .env file and add the following code:

REACT_APP_BITLY_TOKEN = 'enter authorization token here'
REACT_APP_GUID = 'enter guid here'

Enter fullscreen mode Exit fullscreen mode

Guid can be copied from your Bitly account URL https://app.bitly.com/[guid_here]/bitlinks.

Now, add .env to your .gitignore file.

Pushing Repo to GitHub.

  • Run git init in your projects directory to turn our local environment into a repository.

  • Now, go on and log in to your GitHub account and make a new repository.

  • Back in your terminal let's connect the local repository to GitHub, run git remote add origin <url to your GitHub repository>.

  • Change your branch to match the branch on GitHub by running git branch -M main.

  • Run git add --all, to stage your files.

  • Run git commit -m "your_commit_message" to commit your files.

  • Finally, run git push -u origin main to push to GitHub.

Now, refresh your GitHub repo to reflect changes.

Deploying application on Netlify.

  • Go to netlify.com and sign up for an account if you don't already have one.

Netlify

  • Login and navigate to Sites from your dashboard.

  • Click "Import from GitHub" and connect Netlify to GitHub on the page that follows.

  • Next, authorize Netlify and select the repo you just created.

  • Next, Click "Deploy site" to build.

  • After a successful build, Netlify will automatically assign a name to your app, you can change that under Site overview >> Site settings tab >> "Change site name".

Netlify Site settings tab

  • Let's add our environment variables to Netlify. Copy the content of your .env file, go to Site settings >> Environment Variable >> "Add a variable" and select "Import from a .env file", paste your content and click "Import variable".

Netlify Site settings tab

  • Go to the Deploys tab, click "Trigger deploy" and redeploy to use the environment variables in your live app.

Netlify deploys tab

Conclusion.

That's it! If you've made it this far without an error then you have successfully built your link-shortening app. Hurray! 🙌. I encourage you to deploy the application and share it with your friends, you can also share it with me on Twitter @amotabil8.

P.S. If you liked the project do react to my post and if you ran into an error do share a comment and I'll do my best to help you resolve it. ✌️

Resources.

Here's a link to the GitHub repository.

Learn more about React.

Learn more about Bitly's API.

Learn more about Netlify.

Top comments (0)