Skip to content

url shortener written in go (a step towards being friends with go)

License

Notifications You must be signed in to change notification settings

khaled4vokalz/gourl_shortener

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Table of Contents

URL Shortener in Go

Build

This project is a URL Shortener service implemented in Go. It provides RESTful APIs to shorten long URLs and retrieve original URLs using a shortened identifier. The project uses an extensible design with support for multiple storage backends, caching, and configuration management. This is a Go 🐹 learning project for me

Features

  • Shorten URLs: Generate a short, unique URL for any valid original URL.
  • Retrieve Original URLs: Retrieve (get re-directed to) the original URL using the shortened identifier.
  • In-Memory Storage: Default storage backend for rapid prototyping.
  • PostgreSQL Support: Optional storage backend for persistence.
  • Caching with Redis: Reduce database loads by caching
  • Environment Configurations: Support for development and production environments.
  • Extensible Design: Easily swap or add new storage backends.

Prerequisites

  • Go 1.20+
  • Redis for caching (optional, but recommended)
  • PostgreSQL for persistent storage (optional)
  • Make - optional
  • Docker - optional

Running the app

Clone the repository:

$ git clone https://github.com/khaled4vokalz/gourl_shortener.git

Backend

  • Bare Metal:

    • get into server directory

      $ cd gourl_shortener/server
    • install dependencies:

      $ go mod tidy
    • set up configuration: create a configuration file in yaml format or use environment variables for settings like the port, database, and cache.

    • If you're using postgres as storage option, then run the scripts/init-db-script.sh script, so that needed schemas are created. Make sure to pass in the DB_USER, DB_PASSWORD and DB_NAME envs.

    • run the application:

      $ go run ./cmd/gourl_shortener

      Alternatively, we can use make. If you're in the server directory then cd out of it first

      $ cd ..
      $ make run-server
  • Docker

    • build the docker image

      $ docker build --tag go-url-shortener-server .
    • run the container

      $ docker run --detach --env GOURLAPP_storage_type=in-memory --env GOURLAPP_cache_enabled=false --name gourl_shortener --publish 8082:8080 go-url-shortener-server

Frontend

  • Bare Metal:

    • Get into the client directory

      $ cd client
    • Install dependencies (use node 20+)

      $ nvm use 20.0.0
      $ npm ci
    • Start the app

      We can set REACT_APP_BACKEND_URL to the url where the backend api is available, e.g. REACT_APP_BACKEND_URL=http://localhost:8080 before running npm start. By default the app uses http://localhost:8082 as the backend url.

      $ npm start

      Alternatively, we can use make. If you're in the client directory then cd out of it

      $ cd ..
      $ make run-client

    App should be running in development mode. Open http://localhost:3000 to view it in the browser. It's using Hot reload.

  • Docker

    • Get into the client directory

      $ cd client
    • build the docker image

      Build time arg BACKEND_URL may be set to override the default http://localhost:8082 that the app uses as backend url.

      $ docker build --build-arg BACKEND_URL=http://url-where-backend-is-running:port --tag go-url-shortener-client .
    • run the container

      $ docker run --detach --name gourl_shortener_client --publish 3000:80 go-url-shortener-client

    Open http://localhost:3000 to view it in the browser.

Using docker-compose

Running the below command should spin up the containers with needed database and tables in it.

  • The postgres db is listening at port 5433
  • The redis db is listening at port 6380
  • The backend is listening at port 8082
  • The frontend app is listening at 3000
$ POSTGRES_PASSWORD=<your-postgres-pass> DB_PASSWORD=<your-db-pass> docker compose up --detach

API Endpoints

Shorten URL

POST /shorten

  • without Host header

    Request:

    curl --verbose --request POST --data '{"url": "http://example.com"}' localhost:8082/shorten

    Response:

    { "shortened_url": "http://localhost:8082/CBXqmaO8" }
  • with Host header

    Request:

    curl --verbose --request POST --header "Host: https://foo.com" --data '{"url": "http://example.com"}' localhost:8082/shorten

    Response:

    { "shortened_url": "https://foo.com/CBXqmaO8" }

Get Original URL

GET /CBXqmaO8

Response headers:

< HTTP/1.1 308 Permanent Redirect
< Content-Type: text/html; charset=utf-8
< Location: http://example.com

Backend Health Check

GET /health/live

Response (with status code 200):

{ "databaes_is_live": true, "cache_is_alive": true }

Response (with status code 500, in case either/all of the components are not alive):

{ "databaes_is_live": true, "cache_is_alive": false }

Configuration

Backend

  • Configuration can be provided via YAML files or environment variables, currently it only supports config file in the configuration directory having the same name of the ENVIRONMENT env. Example YAML configuration:
server:
  host: localhost
  port: 8080
storage:
  type: postgres
  dbConnString: "user=shortener password=<pass> dbname=gourl_shortener sslmode=disable"
cache:
  enabled: true
  host: localhost
  port: 6379
  database: 0
shortenerProps:
  length: 6 # the total bytes that should be considered from the SHA256 hash of the url
  maxAttempt: 5 # maximum attempt the service should take when key collision happens for a url
environment: dev # the environment of the application, either `dev` or `prod`.
  • Override configurations using Environment Variables

Any configuration mentioned above can be overridden using Environment variables using GOURLAPP_ prefix and use the property tree separated by underscores (_). e.g. If we want to override maxAttempt configuration, we can set it like GOURLAPP_shortenerProps_maxAttempt=10

Frontend

  • only REACT_APP_BACKEND_URL environment variable that can override the backend url the app should talk to

Testing

Backend

Run unit tests with:

$ make test-server

If you don't have make you can get inside the server directory and run

$ cd gourl_shortener/server
$ go test ./...

Roadmap

  • [] Implement analytics for shortened URLs (e.g., number of clicks)
  • Add expiration time
  • Add a web UI for managing shortened URLs
  • Add support for Environment variables in the config files
  • Add docker support
  • Add logging
  • Health-check
  • [] House keeping
    • [] Provide default values for the configurations, probably my having a separate config manager

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

url shortener written in go (a step towards being friends with go)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published