A URL shortener API built with NestJS and TypeScript, featuring PostgreSQL for relational data storage and DynamoDB for distributed storage capabilities.
- URL Shortener
- URL shortening and redirection
- PostgreSQL database integration
- DynamoDB support for scalable storage
- RESTful API endpoints
- Comprehensive test coverage
- CircleCI integration
- Framework: NestJS
- Language: TypeScript
- Databases: PostgreSQL, AWS DynamoDB
- Containerization: Docker
- CI/CD: CircleCI
- Testing: Jest
- Node.js (v20 or higher)
- Yarn
- Docker and Docker Compose
- AWS CLI (for DynamoDB local development)
yarn installAdd environment variables to CircleCI under jobs.build-and-test.environment in .circleci/config.yml.
Create a .env file in the root directory of this project with the required environment variables.
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 -dIf 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 deniedRun the following command to fix:
sudo chmod -R 777 ./docker/postgres/dataIn the local environment, we use Localstack to emulate AWS DynamoDB.
Check for Localstack AWS Profile
aws configure list --profile localstackExpected 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 = dummyAdd the following to ~/.aws/config:
[profile localstack]
region = us-east-1
output = jsonCreate 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=5Insert 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 ShortLinkList all tables:
aws dynamodb list-tables \
--endpoint-url=http://localhost:4566 \
--region=us-east-1 \
--profile localstackCreate 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_tableRun pending migrations:
npm run migration:upRevert the last migration:
npm run migration:down# Development mode
npm run start
# Watch mode (auto-reload on changes)
npm run start:dev
# Production mode
npm run start:prod# Unit tests
yarn test
# E2E tests
yarn test:e2e
# Test coverage
yarn test:covcircleci local execute build-and-testWhen 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- How to Build a Type-Safe URL Shortener in Node.js with NestJS
- URL Shortening System Design
- System Design: URL Shortener
Cuong Le - kanelv