Skip to content

A scalable URL shortener API built with NestJS and TypeScript, featuring dual database support (PostgreSQL and DynamoDB) for flexible storage options, comprehensive testing, and CI/CD integration.

License

Notifications You must be signed in to change notification settings

kanelv/url-shortener-backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

URL Shortener

A URL shortener API built with NestJS and TypeScript, featuring PostgreSQL for relational data storage and DynamoDB for distributed storage capabilities.

Table of Contents

Features

  • URL shortening and redirection
  • PostgreSQL database integration
  • DynamoDB support for scalable storage
  • RESTful API endpoints
  • Comprehensive test coverage
  • CircleCI integration

Tech Stack

  • Framework: NestJS
  • Language: TypeScript
  • Databases: PostgreSQL, AWS DynamoDB
  • Containerization: Docker
  • CI/CD: CircleCI
  • Testing: Jest

Prerequisites

  • Node.js (v20 or higher)
  • Yarn
  • Docker and Docker Compose
  • AWS CLI (for DynamoDB local development)

Installation

yarn install

Setup

Environment Variables

CircleCI

Add environment variables to CircleCI under jobs.build-and-test.environment in .circleci/config.yml.

Local Development

Create a .env file in the root directory of this project with the required environment variables.

Database Setup

PostgreSQL with Docker

Run the following commands to set up a PostgreSQL Docker container:

# Give execute permission to the initialization script
chmod +x ./docker/postgres/init/1_connect.sh

# Start PostgreSQL container (port: 5432)
docker-compose -f ./docker/docker-compose.yml up -d

Troubleshooting: "Permission denied" Error on macOS

If you encounter permission errors when running Docker on macOS:

chmod: /var/lib/postgresql/data: Permission denied
find: /var/lib/postgresql/data: Permission denied
chown: /var/lib/postgresql/data: Permission denied

Run the following command to fix:

sudo chmod -R 777 ./docker/postgres/data

AWS DynamoDB Setup

Localstack Configuration

In the local environment, we use Localstack to emulate AWS DynamoDB.

Check for Localstack AWS Profile

aws configure list --profile localstack

Expected output:

      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile               localstack           manual    --profile
access_key     ****************ummy shared-credentials-file
secret_key     ****************ummy shared-credentials-file
    region                us-east-1      config-file    ~/.aws/config

Configure Localstack Profile (if not already set up)

Add the following to ~/.aws/credentials:

[localstack]
aws_access_key_id = dummy
aws_secret_access_key = dummy

Add the following to ~/.aws/config:

[profile localstack]
region = us-east-1
output = json

Create DynamoDB Table

Create the ShortLink table in Localstack:

aws dynamodb create-table \
    --endpoint-url=http://localhost:4566 \
    --region=us-east-1 \
    --profile localstack \
    --table-name ShortLink \
    --attribute-definitions \
        AttributeName=shortCode,AttributeType=S \
        AttributeName=createdAt,AttributeType=N \
    --key-schema \
        AttributeName=shortCode,KeyType=HASH \
        AttributeName=createdAt,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=5,WriteCapacityUnits=5

DynamoDB Utility Commands

Insert a test item:

aws dynamodb put-item \
    --endpoint-url=http://localhost:4566 \
    --region=us-east-1 \
    --profile localstack \
    --table-name ShortLink \
    --item '{"shortCode":{"S":"abc123"},"createdAt":{"N":"1234567890"},"originalUrl":{"S":"https://example.com"}}'

List all items in the table:

aws dynamodb scan \
    --endpoint-url=http://localhost:4566 \
    --region=us-east-1 \
    --profile localstack \
    --table-name ShortLink

List all tables:

aws dynamodb list-tables \
    --endpoint-url=http://localhost:4566 \
    --region=us-east-1 \
    --profile localstack

Database Migrations

Generate New Migration

Create a new migration script for database schema changes:

npm run migration:generate src/infra/frameworks/database/migrations/<migration_name>

Examples:

npm run migration:generate src/infra/frameworks/database/migrations/change_userName_to_username_on_user_table

npm run migration:generate src/infra/frameworks/database/migrations/change_id_to_string_on_user_table

Apply Migrations

Run pending migrations:

npm run migration:up

Rollback Migrations

Revert the last migration:

npm run migration:down

Running the Application

# Development mode
npm run start

# Watch mode (auto-reload on changes)
npm run start:dev

# Production mode
npm run start:prod

Testing

# Unit tests
yarn test

# E2E tests
yarn test:e2e

# Test coverage
yarn test:cov

CI/CD

Running CircleCI Locally

circleci local execute build-and-test

Debug with SSH on CircleCI

When you enable SSH in a CircleCI build, connect using:

ssh -i ~/.ssh/id_ed25519_kanelv -p <PORT> <IP_ADDRESS>

Example:

ssh -i ~/.ssh/id_ed25519_kanelv -p 64535 34.227.75.120

References

System Design & Architecture

Database Hosting

Author

Cuong Le - kanelv

About

A scalable URL shortener API built with NestJS and TypeScript, featuring dual database support (PostgreSQL and DynamoDB) for flexible storage options, comprehensive testing, and CI/CD integration.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages