Skip to main content
Lesson 1 of 2Advanced⏱ 45 mins

Project: URL Shortener

A complete URL shortener project.

0% of path

Learning Objectives

  • Build a full app

##Project: URL Shortener API

In this project, we'll outline how to build a URL Shortener—a classic web application that takes a long URL and generates a short, unique alias. When users visit the alias, they are redirected to the original URL.

This project combines routing, state management, and database integration.

#Core Requirements

  1. 1
    POST `/api/shorten`: Accepts a long URL and returns a short URL.
  2. 2
    GET `/{alias}`: Looks up the long URL by its alias and redirects the user (HTTP 301 or 302).
  3. 3
    Storage: A database (e.g., PostgreSQL using SQLx or SQLite) to persist the mappings.

#State and Database

We need an AppState to hold our database pool.

code_blocksrust
use sqlx::PgPool;

struct AppState {
    db: PgPool,
}

#The Shorten Endpoint

To create a short alias, we can generate a random string or hash the database ID. The nanoid crate is great for this.

code_blocksrust
use actix_web::{post, web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use nanoid::nanoid;

#[derive(Deserialize)]
struct ShortenReq {
    url: String,
}

#[derive(Serialize)]
struct ShortenRes {
    short_url: String,
}

#[post("/api/shorten")]
async fn shorten_url(
    req: web::Json<ShortenReq>,
    state: web::Data<AppState>
) -> impl Responder {
    let alias = nanoid!(6); // Generate 6-char ID
    
    // Insert into DB: alias -> req.url
    // e.g., sqlx::query!("INSERT INTO urls ...")
    
    HttpResponse::Ok().json(ShortenRes {
        short_url: format!("http://localhost:8080/{}", alias),
    })
}

#The Redirect Endpoint

When a request comes in for /{alias}, we extract the alias, look up the original URL, and return a redirect.

code_blocksrust
use actix_web::{get, web, HttpResponse, Responder};

#[get("/{alias}")]
async fn redirect_url(
    path: web::Path<String>,
    state: web::Data<AppState>
) -> impl Responder {
    let alias = path.into_inner();
    
    // Fetch original URL from DB using `alias`
    let original_url = "https://example.com"; // Mocked
    
    // Return a 302 Found redirect
    HttpResponse::Found()
        .append_header(("Location", original_url))
        .finish()
}

By combining these concepts, you have a fully functional URL shortener API!

Practical Exercise

Build a Shortener Endpoint

Task

Requirements

    Try solving the exercise in your local environment first. Once you have a solution, or if you get completely stuck, reveal the answer.

    Key Takeaways

    • Use `web::Json` to accept long URLs from the client.
    • Use `web::Path` to capture the short alias in the redirect route.
    • `HttpResponse::Found()` (302) is used to redirect users to the original destination.
    • Application state (`web::Data`) is perfect for sharing the database connection pool across these endpoints.

    Finished reading?

    Mark this lesson as done to track your progress and earn XP.