Build a Simple Next.js Interactive Web-Based URL Shortener

Written by

in

In the digital age, sharing long, unwieldy URLs is a common inconvenience. Whether you’re tweeting a link, sharing it on messaging apps, or simply trying to make a URL more manageable, a long URL can be a real pain. This is where URL shorteners come in handy. They transform lengthy web addresses into concise, shareable links. This tutorial will guide you through building a simple, interactive URL shortener using Next.js, a powerful React framework, enabling you to learn fundamental web development concepts while creating a practical tool.

Why Build a URL Shortener?

Building a URL shortener isn’t just a fun project; it’s a valuable learning experience. Here’s why you should consider it:

  • Practical Application: You’ll create a tool you can use daily to simplify your online sharing.
  • Learning Core Concepts: You’ll get hands-on experience with frontend and backend development, API interactions, and state management.
  • Understanding Modern Web Development: You’ll become familiar with Next.js, a popular framework for building modern web applications.
  • SEO Benefits: Shorter URLs can sometimes be beneficial for SEO, particularly in situations where character limits are a constraint.

Prerequisites

Before you begin, make sure you have the following:

  • Node.js and npm (or yarn): These are essential for running JavaScript and managing project dependencies.
  • A Code Editor: Such as VS Code, Sublime Text, or Atom.
  • Basic Knowledge of HTML, CSS, and JavaScript: Familiarity with these languages is necessary to understand the code.
  • A free account with a URL shortening service API: We’ll be using a free API for this project.

Setting Up Your Next.js Project

Let’s start by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app url-shortener-app

This command creates a new Next.js project named “url-shortener-app”. Navigate into your project directory:

cd url-shortener-app

Now, let’s install the necessary dependencies. We’ll use Axios for making API requests. Run the following command:

npm install axios

Project Structure

Your project structure should look like this:

url-shortener-app/
├── node_modules/
├── pages/
│   ├── _app.js
│   ├── index.js
│   └── api/
│       └── shorten.js
├── public/
├── styles/
│   ├── globals.css
│   └── Home.module.css
├── .gitignore
├── next.config.js
├── package-lock.json
├── package.json
└── README.md

We’ll be primarily working in the `pages/` directory. `index.js` will contain the main UI, and we’ll create an API route in `pages/api/shorten.js` to handle the URL shortening logic.

Creating the Frontend (index.js)

Let’s build the frontend. Open `pages/index.js` and replace the default content with the following code:

import { useState } from 'react';
import axios from 'axios';
import styles from '../styles/Home.module.css';

export default function Home() {
  const [longUrl, setLongUrl] = useState('');
  const [shortUrl, setShortUrl] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    setIsLoading(true);
    setError('');
    setShortUrl('');

    try {
      const response = await axios.post('/api/shorten', { longUrl });
      setShortUrl(response.data.shortUrl);
    } catch (err) {
      setError(err.response?.data?.error || 'An error occurred. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div>
      <main>
        <h1>URL Shortener</h1>
        <p>Shorten your long URLs with ease!</p>
        
           setLongUrl(e.target.value)}
            placeholder="Enter your long URL"
            required
            className={styles.input}
          />
          <button type="submit" disabled="{isLoading}">
            {isLoading ? 'Shortening...' : 'Shorten'}
          </button>
          {error && <p>{error}</p>}
          {shortUrl && (
            <div>
              <p>Shortened URL: <a href="{shortUrl}" target="_blank" rel="noopener noreferrer">{shortUrl}</a></p>
            </div>
          )}
        
      </main>
    </div>
  );
}

Let’s break down this code:

  • State Variables: We use the `useState` hook to manage the `longUrl`, `shortUrl`, `isLoading`, and `error` states.
  • Input Field: An input field allows users to enter the long URL.
  • Submit Button: The button triggers the `handleSubmit` function.
  • Form Submission: The `handleSubmit` function sends a POST request to the `/api/shorten` API route (which we’ll create next) with the `longUrl`.
  • Error Handling: We display an error message if the API request fails.
  • Displaying the Shortened URL: If the API request is successful, the shortened URL is displayed as a clickable link.
  • Loading State: The button is disabled and shows “Shortening…” while the request is in progress.

Creating the Backend (api/shorten.js)

Now, let’s create the backend API route. Create a new file named `shorten.js` inside the `pages/api/` directory (i.e., `pages/api/shorten.js`) and add the following code:

import axios from 'axios';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { longUrl } = req.body;

    if (!longUrl) {
      return res.status(400).json({ error: 'Please provide a URL.' });
    }

    try {
      // Replace with your preferred URL shortener API.
      const apiKey = process.env.URL_SHORTENER_API_KEY; // Store your API key securely
      const apiUrl = `https://api.shrtco.de/v2/shorten?url=${encodeURIComponent(longUrl)}`;

      const response = await axios.get(apiUrl);

      if (response.data.ok) {
          const shortUrl = response.data.result.short_link;
          return res.status(200).json({ shortUrl });
      } else {
          return res.status(500).json({ error: response.data.error });
      }
    } catch (error) {
      console.error('API Error:', error);
      return res.status(500).json({ error: 'Failed to shorten URL. Please check the URL and try again.' });
    }
  } else {
    res.setHeader('Allow', ['POST']);
    res.status(405).end(`Method ${req.method} Not Allowed`);
  }
}

Let’s break down this code:

  • Import Axios: We import `axios` to make API requests to the URL shortening service.
  • API Route Handler: This function handles incoming requests to the `/api/shorten` route.
  • Method Check: It only accepts POST requests.
  • Input Validation: It checks if a `longUrl` is provided in the request body.
  • API Request: It makes a GET request to the shrtco.de API to shorten the URL. You’ll need to sign up for a free API key at shrtco.de and replace the placeholder with your actual API key, in a .env file.
  • Error Handling: It handles potential errors during the API request and returns an appropriate error response.
  • Response: If the shortening is successful, it returns the shortened URL in the response.

Important: For production use, it’s crucial to store your API key securely. The best practice is to use environment variables. In your project, create a `.env.local` file in the root directory and add your API key like this:

URL_SHORTENER_API_KEY=YOUR_API_KEY_HERE

Then, in your `api/shorten.js` file, you can access the key using `process.env.URL_SHORTENER_API_KEY`.

Styling the Application (styles/Home.module.css)

To make the application visually appealing, let’s add some basic styling. Open `styles/Home.module.css` and replace its content with the following:

.container {
  min-height: 100vh;
  padding: 0 0.5rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: #f0f0f0;
}

.main {
  padding: 5rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 80%;
  max-width: 600px;
  background-color: white;
  border-radius: 10px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
}

.title {
  margin: 0;
  line-height: 1.15;
  font-size: 3rem;
  text-align: center;
  color: #333;
}

.description {
  text-align: center;
  font-size: 1.2rem;
  color: #666;
  margin-bottom: 2rem;
}

.form {
  display: flex;
  flex-direction: column;
  width: 80%;
}

.input {
  padding: 0.75rem 1rem;
  font-size: 1rem;
  border: 1px solid #ccc;
  border-radius: 5px;
  margin-bottom: 1rem;
}

.button {
  padding: 0.75rem 1rem;
  font-size: 1rem;
  background-color: #0070f3;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}

.button:hover:not(:disabled) {
  background-color: #0056b3;
}

.error {
  color: red;
  margin-top: 1rem;
  text-align: center;
}

.shortUrlContainer {
  margin-top: 1rem;
  text-align: center;
}

.shortUrlContainer a {
  color: #0070f3;
  text-decoration: none;
}

.shortUrlContainer a:hover {
  text-decoration: underline;
}

This CSS provides a clean and user-friendly interface. Feel free to customize the styles to your liking.

Running Your Application

Now, let’s run your application. In your terminal, make sure you’re in the project directory and run the following command:

npm run dev

This command starts the Next.js development server. Open your web browser and go to `http://localhost:3000`. You should see your URL shortener application. Enter a long URL, click “Shorten,” and you should see the shortened URL displayed below, which, when clicked, will redirect to the original URL.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • API Key Issues: Double-check that you’ve correctly entered your API key in the `.env.local` file and that you’re referencing it correctly in your `api/shorten.js` file (using `process.env.URL_SHORTENER_API_KEY`). Also, make sure the API key is valid.
  • CORS Errors: If you encounter CORS (Cross-Origin Resource Sharing) errors, ensure that the URL shortening API you’re using allows requests from your domain. Some APIs require you to specify your domain in their settings.
  • Incorrect URL Formatting: The URL you enter must be a valid URL, including the `http://` or `https://` prefix.
  • Network Errors: If you get network errors, check your internet connection and ensure the URL shortening API service is operational.
  • Typos: Carefully check your code for any typos, especially in the API endpoint URLs and variable names.
  • Missing Dependencies: Make sure you’ve installed all the required dependencies (e.g., Axios).

Key Takeaways and Summary

You’ve successfully built a simple URL shortener using Next.js! You’ve learned how to:

  • Set up a Next.js project.
  • Create a frontend with an input field, a button, and a display area for the shortened URL.
  • Create a backend API route to handle the URL shortening logic.
  • Use the Axios library to make API requests to a URL shortening service.
  • Handle user input and display the results.
  • Implement basic error handling.
  • Use environment variables to securely store API keys.

FAQ

  1. Can I use a different URL shortening API? Yes, you can! Simply replace the API endpoint and any related parameters in the `api/shorten.js` file with the details of your chosen API. Make sure to read the API documentation carefully.
  2. How can I deploy this application? You can deploy your Next.js application to platforms like Vercel (recommended, as it’s built by the same company), Netlify, or other hosting providers that support Next.js.
  3. What are some other features I could add? You could add features such as custom short URL creation (if the API supports it), URL analytics (if the API provides them), a history of shortened URLs, and user authentication.
  4. How can I make the app more secure? Besides using environment variables for API keys, you could add input validation to sanitize user input and prevent potential security vulnerabilities. Consider rate limiting API requests to prevent abuse.

Building this project is a solid foundation for understanding web development concepts and working with Next.js. You can expand on this project by adding more features, improving the user interface, and exploring more advanced techniques. The ability to create and deploy practical tools like this is a valuable skill in today’s digital landscape.