Building a URL Shortener

Table Of Content
- URL Shortener with Spring Boot
- Step 1: Setting Up the Project
- Project Setup:
- Import the Project:
- Step 2: Creating the `ShortUrl` Entity
- Entity Class: `ShortUrl.java`
- Step 3: Creating the `UrlService` Interface
- Service Interface: `UrlService.java`
- Step 4: Creating the Repository
- Repository: `JpaRepo.java`
- Step 5: Implementing the URL Shortening Logic
- Service: `UrlServiceImpl.java`
- Explanation:
- `saveUrl(String longUrl)`
- `getShortUrl(String shortUrl)`
- `hashId(Long id)`
- URL Shortener API Endpoints
- 1. Create Shortened URL
- 2. Retrieve Long URL
URL Shortener with Spring Boot
In this blog, we walk through the process of building a URL Shortener application using Spring Boot and JPA. You will learn how to:
- Hash long URLs into shorter versions.
- Persist URL data in an in-memory H2 database.
- Create a REST API for shortening and retrieving URLs.
Step 1: Setting Up the Project
To get started, we will create a Spring Boot project with the necessary dependencies using start.spring.io.
Project Setup:
- Go to start.spring.io.
- Choose the following configurations:
- Project Type: Maven
- Language: Java
- Spring Boot Version: Use the latest stable version
- Group:
com.sid121212 - Artifact:
url-shortener
- Under Dependencies, add the following:
- Spring Web: For creating REST APIs
- Spring Data JPA: For database interaction
- H2 Database: For an in-memory database
- Click Generate to download the project.
Import the Project:
- Unzip the downloaded project.
- Open it in your favorite IDE (IntelliJ, Eclipse, etc.).
- Once opened, the project structure will have all the necessary Spring Boot configurations to begin.
Now that we have the basic setup ready, let’s move on to building the core URL Shortener functionality.
Step 2: Creating the ShortUrl Entity
In this step, we will create the ShortUrl entity, which will represent the data model for storing long URLs and their corresponding shortened versions.
Entity Class: ShortUrl.java
In the src/main/java/com/sid121212/url_shortner/ directory, create a file named ShortUrl.java with the following content:
package com.sid121212.url_shortner;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class ShortUrl {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String hashedId;
private String longUrl;
public ShortUrl(Long id, String hashedId, String longUrl) {
this.id = id;
this.hashedId = hashedId;
this.longUrl = longUrl;
}
public ShortUrl() {
// Default constructor required by JPA
}
public ShortUrl(String longUrl) {
this.longUrl = longUrl;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getHashedId() {
return hashedId;
}
public void setHashedId(String hashedId) {
this.hashedId = hashedId;
}
public String getLongUrl() {
return longUrl;
}
public void setLongUrl(String longUrl) {
this.longUrl = longUrl;
}
}Step 3: Creating the UrlService Interface
Now that we have the ShortUrl entity, the next step is to define the service layer that will handle the business logic for saving and retrieving shortened URLs. We'll start by creating an interface for the service.
Service Interface: UrlService.java
In the src/main/java/com/sid121212/url_shortner/controller/service/ directory, create a file named UrlService.java with the following content:
package com.sid121212.url_shortner.controller.service;
public interface UrlService {
public String saveUrl(String longUrl);
public String getShortUrl(String hashedId);
}Step 4: Creating the Repository
To interact with the database, we'll need a repository to handle CRUD operations for the ShortUrl entity. We'll use Spring Data JPA for this purpose.
Repository: JpaRepo.java
In the src/main/java/com/sid121212/url_shortner/controller/repo/ directory, create a file named JpaRepo.java with the following content:
package com.sid121212.url_shortner.controller.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.sid121212.url_shortner.ShortUrl;
public interface JpaRepo extends JpaRepository<ShortUrl, Long> {
@Query("SELECT s.longUrl FROM ShortUrl s WHERE s.hashedId = :hashedId")
String getByHashedId(String hashedId);
}Step 5: Implementing the URL Shortening Logic
The core functionality of the URL shortener lies in its service layer. This is where we handle the logic for converting long URLs into short ones and retrieving them back. Let’s walk through the service implementation.
Service: UrlServiceImpl.java
In the src/main/java/com/sid121212/url_shortner/controller/service/ directory, create a file named UrlServiceImpl.java with the following content:
Explanation:
saveUrl(String longUrl)
-
Create ShortUrl Entity: When a long URL is provided, a new
ShortUrlentity is created with the provided long URL. -
Save Entity: The entity is saved using the repository (
urlRepo.save(shortUrl)), which automatically generates a unique ID for the record. -
Generate Hashed ID: We generate a hashed ID by converting the generated ID into a hexadecimal string using the
hashId()method. -
Update Entity: The generated hashed ID is set for the entity. The entity is then updated in the database with this hashed ID.
-
Return Shortened URL: Finally, the service returns a shortened URL that includes the hashed ID (e.g.,
https://urlshortner/hashedId).
getShortUrl(String shortUrl)
-
Extract Hashed ID: When a shortened URL is requested, the hashed ID is extracted from the URL string using the
getHashedIdFromShortUrl()method. -
Retrieve Long URL: This hashed ID is used to retrieve the corresponding long URL from the database by calling
urlRepo.getByHashedId(hashedId).
hashId(Long id)
- Convert ID to Hashed Format: This method converts the generated ID into a hashed format, such as a hexadecimal string, to create a short and unique identifier for the URL.
package com.sid121212.url_shortner.controller.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sid121212.url_shortner.ShortUrl;
import com.sid121212.url_shortner.controller.repo.JpaRepo;
@Service
public class UrlServiceImpl implements UrlService {
@Autowired
private JpaRepo urlRepo;
@Override
public String getShortUrl(String shortUrl) {
String hashedId = getHashedIdFromShortUrl(shortUrl);
return urlRepo.getByHashedId(hashedId);
}
private String getHashedIdFromShortUrl(String shortUrl) {
int lastSlashIndex = shortUrl.lastIndexOf("/");
if (lastSlashIndex != -1 && lastSlashIndex + 1 < shortUrl.length()) {
return shortUrl.substring(lastSlashIndex + 1);
}
return null;
}
@Override
public String saveUrl(String longUrl) {
ShortUrl shortUrl = new ShortUrl(longUrl);
ShortUrl savedUrl = urlRepo.save(shortUrl);
// Generate a hashed ID based on the saved entity's generated ID
String hashedId = hashId(savedUrl.getId());
// Update the entity with the hashed ID and save it again
savedUrl.setHashedId(hashedId);
urlRepo.save(savedUrl);
return "https://urlshortner/" + hashedId;
}
private String hashId(Long id) {
return Long.toHexString(id); // Convert ID to hex as an example
}
}URL Shortener API Endpoints
1. Create Shortened URL
Endpoint: POST /url
Description: This endpoint receives a long URL and returns a shortened URL.
Request Body:
- Content-Type:
application/json - Body:
{ "longUrl": "https://example.com/very-long-url" }
**Response**:
- **Status Code**: `200 OK`
- **Body**:
```json
"https://example.com/abcd1234"
2. Retrieve Long URL
Endpoint: GET /url
Description: This endpoint retrieves the original long URL from a given shortened URL.
Query Parameters:
- shortUrl: The shortened URL whose original long URL is to be retrieved.
Example Request:
- URL:
/url?shortUrl=https://urlshortner/abcd1234
Response:
- Status Code:
200 OK - Body:
"https://example.com/very-long-url"
With this URL shortener service, you can easily create short links and retrieve long URLs, you can also add checks like if there is repetative long url then no need to create another shortUrl and so on. Try integrating it into your projects for efficient URL handling!
