Interview Question: Build a Simple URL Shortener in Go

Publish date: 2024-11-20
Tags: Go, Interview-Questions

In this blog post, we will build a simple URL shortener in Go. This will demonstrate how to generate short codes for long URLs, store them in memory, and retrieve the original URL from the short code. We will also ensure thread-safety for concurrent access to the in-memory store using sync.Mutex.

This question was asked to me by Radisys for the role of Golang Developer.


Step 1: Data Structure for Storing URLs

First, we need a place to store the URLs. Since we want our URL shortener to be fast and simple, we will use an in-memory map to store the mapping between the short codes and the original URLs. We also need a way to safely access this map in a multi-threaded environment, which is where sync.Mutex comes in.

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// A map to store URLs in memory
var urlStore = make(map[string]string)
var mu sync.Mutex // Mutex to handle concurrent access

Step 2: Generate a Short Code

To shorten the URL, we need to generate a short code. The short code will be a random alphanumeric string. We will define a function to generate this random string and ensure that it is unique before storing it.

// Initialize the random seed
func init() {
	rand.Seed(time.Now().UnixNano())
}

// Generates a random string of fixed length (short code)
func generateShortCode(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	code := make([]byte, length)
	for i := range code {
		code[i] = charset[rand.Intn(len(charset))]
	}
	return string(code)
}

Step 3: Store the URL Mapping

Once we have a short code, we need to store the mapping between the short code and the long URL. To ensure uniqueness, we will check if the generated short code already exists in the urlStore map. If it does, we generate a new code.

// ShortenURL takes a long URL and returns a short code
func ShortenURL(longURL string) string {
	mu.Lock()
	defer mu.Unlock()

	// Generate a unique short code
	shortCode := generateShortCode(6)
	for urlStore[shortCode] != "" { // Ensure uniqueness
		shortCode = generateShortCode(6)
	}

	// Store the mapping in memory
	urlStore[shortCode] = longURL
	return shortCode
}

Step 4: Retrieve the Original URL

To retrieve the original URL from the short code, we will define a function that looks up the short code in the urlStore map. If the short code exists, it will return the corresponding long URL.

// GetOriginalURL retrieves the original URL from a short code
func GetOriginalURL(shortCode string) (string, bool) {
	mu.Lock()
	defer mu.Unlock()

	longURL, exists := urlStore[shortCode]
	return longURL, exists
}

Step 5: Putting It All Together

Now that we have all the necessary functions, let’s put everything together in the main function. We will demonstrate how to shorten a URL and retrieve the original URL using the generated short code.

// Main for demonstration
func main() {
	// Shorten a URL
	longURL := "https://example.com"
	shortCode := ShortenURL(longURL)
	fmt.Printf("Short code for %s: %s\n", longURL, shortCode)

	// Retrieve the original URL
	originalURL, exists := GetOriginalURL(shortCode)
	if exists {
		fmt.Printf("Original URL for short code %s: %s\n", shortCode, originalURL)
	} else {
		fmt.Println("Short code not found!")
	}
}

Example Output:

Short code for https://example.com: aB3cD1
Original URL for short code aB3cD1: https://example.com

Conclusion

In this post, we have built a simple URL shortener in Go. The key features of this implementation include:

Advantages

Limitations


Possible Extensions

Tags: Go, Interview-Questions