node-url-shortener/
│
├── api/
│ ├── controllers/
│ │ └── UrlController.js
│ ├── models/
│ │ └── Url.js
│ └── helpers/
│ └── base58.js
│
├── config/
│ ├── env/
│ │ ├── development.js
│ │ ├── index.js
│ │ ├── production.js
│ │ └── test.js
│ ├── middleware/
│ │ └── errorHandler.js
│ ├── routes/
│ │ ├── index.js
│ │ └── url.js
│ ├── database.js * Sequelize CLI (migrations)
│ ├── express.js
│ └── sequelize.js
│
├── migrations/ * Sequelize migrations
├── seeders/
├── view/
│ ├── css/
│ ├── javascript/
│ │ └── shorten.js
│ └── index.html
│
├── test/
│ └── url.test.js
│
├── .eslintrc.json
├── .gitignore
├── .sequelizerc
├── index.js * Application entry point
├── LICENSE
├── package.json
├── package-lock.json
└── README.md
URL shortening turns a long URL into a shorter one that redirects to the original. The short link is easier to share and remember.
The database stores each URL with an auto-increment numeric id. The short code in the path is that id encoded in Base58 (alphanumeric, excluding ambiguous characters like 0, O, I, l). When someone opens /:encodedId, the server decodes it to id, loads the row, and redirects to longUrl.
There is a unique index on longUrl so the same URL is never stored twice; concurrent POST requests are handled with findOrCreate and a fallback if a uniqueness race occurs.
- Node.js 18 or newer (LTS recommended)
- MySQL 5.7+ or 8.x
| Variable | Description | Default (from env files) |
|---|---|---|
NODE_ENV |
development, test, or production |
development |
PORT |
HTTP port | 3000 |
DB_HOST |
MySQL host | localhost |
DB_PORT |
MySQL port | 3306 |
DB_NAME |
Database name | shortener_dev / shortener_test / shortener by environment |
DB_USER |
MySQL user | root |
DB_PASSWORD |
MySQL password | root (override in production) |
PUBLIC_URL or BASE_URL |
Public base URL for short links (no trailing slash), e.g. https://short.example.com |
If unset, derived from the incoming request (req.protocol and Host) |
TRUST_PROXY |
Set to true or 1 if the app sits behind a reverse proxy so X-Forwarded-* is honored |
unset |
Copy values into a .env file or your host’s secret manager. The .env file is gitignored; do not commit real passwords.
- Clone the repository:
git clone https://github.com/murraco/node-url-shortener.git
cd node-url-shortener- Install dependencies:
npm install- Configure the database using the variables above (optional
.envor shell exports). The files underconfig/env/only supply defaults and read fromprocess.env.
docker run -d --name mysql-shortener \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=root \
mysql:8Create the databases (adjust user/password if needed):
docker exec -it mysql-shortener mysql -uroot -proot -e "
CREATE DATABASE IF NOT EXISTS shortener_dev;
CREATE DATABASE IF NOT EXISTS shortener_test;
CREATE DATABASE IF NOT EXISTS shortener;
"After MySQL is running and credentials match config/env (or your env vars), apply the schema:
npm run migrateIn development only, the app also runs sequelize.sync() on startup so tables are created if missing. Production does not sync on startup; run migrations before deploying.
- Production-style:
npm start→ runsnode index.js(connects to DB, nosyncwhenNODE_ENV=production). - Development with reload:
npm run dev→nodemon index.js.
Then open http://localhost:3000 (or your PORT).
Health check. Response: { "status": "ok" }
Creates or returns an existing short link for a URL.
- Body (JSON):
{ "url": "https://example.com/path" } - Success:
201—{ "shortUrl": "<public-base>/<base58-id>" } - Errors:
400—{ "error": "..." }for missing/invalid URL or non-http(s) scheme - Server errors:
500—{ "error": "Internal server error" }
Register new single-segment routes before /:encodedId in the router so they are not treated as short codes.
Redirects (302) to the stored URL, or to the site root if the code is unknown.
Tests use NODE_ENV=test (see test/url.test.js), the shortener_test database (unless overridden with DB_NAME), and Url.sync({ force: true }) in a before hook to reset the table.
Requirements: MySQL running and the test database created.
npm testnpm audit was run after dependency updates; a few advisories may remain in transitive dev dependencies (for example Mocha). Re-run npm audit periodically.
- Report issues
- Open pull requests with improvements
- Contact: mauriurraco@gmail.com
