A RESTful URL shortening service built with Node.js, Express, and TypeScript, backed by a PostgreSQL database (via Neon). Features user authentication with JWT, URL shortening with nanoid, and admin analytics with geographic and device tracking.
- User Authentication — Register and log in with JWT-based auth and bcrypt password hashing
- URL Shortening — Generate short IDs for long URLs using nanoid
- URL Resolution — Redirect from a short URL to its original destination
- Click Analytics — Log device, OS, country, and city per click (via
geoip-liteandua-parser-js) - Admin Dashboard — Query per-URL click analytics (admin-only endpoint)
| Layer | Technology |
|---|---|
| Runtime | Node.js + TypeScript (ts-node) |
| Framework | Express |
| Database | PostgreSQL (Neon serverless) |
| Auth | JSON Web Tokens + bcrypt |
| Short IDs | nanoid |
| Geo / UA | geoip-lite, ua-parser-js |
| Linting | ESLint + typescript-eslint |
src/
├── index.ts # Entry point, route mounting
├── middleware.ts # JWT authenticator, admin checker, request logger
├── routes/
│ ├── authRoutes.ts # POST /auth/signup, POST /auth/login
│ ├── userRoutes.ts # POST /url/shorten, GET /url/:id
│ └── adminRoutes.ts # GET /analytics/:id
├── controllers/
│ ├── authController.ts
│ ├── userController.ts
│ └── adminController.ts
├── models/
├── services/
├── configs/
└── types/
dbschema.sql # PostgreSQL schema (users, urls, logs)
openapi3_0.yaml # OpenAPI 3.0 API documentation
| Method | Path | Auth Required | Description |
|---|---|---|---|
| POST | /auth/signup |
No | Register a new user |
| POST | /auth/login |
No | Log in and receive a JWT |
| POST | /url/shorten |
Yes | Shorten a long URL |
| GET | /url/:id |
Yes | Resolve a short URL (logs the click) |
| GET | /analytics/:id |
Yes (Admin) | Get click analytics for a short URL |
Full API documentation is available in
openapi3_0.yaml. Upload it to Swagger Editor for an interactive view.
Three tables are defined in dbschema.sql:
users— Stores registered users (id,username,password,isAdmin)urls— Stores short-to-long URL mappings (id,longUrl)logs— Records each click with device, OS, country, city, and timestamp
- Node.js (v18+)
- A PostgreSQL database (e.g. Neon)
- Postman (desktop) for testing
-
Clone the repository and install dependencies:
git clone <repo-url> cd urlShortner npm install
-
Configure environment variables:
Create a
.envfile in the root:DATABASE_URL=<your-neon-postgres-connection-string> JWT_SECRET=<your-secret-key>
-
Initialize the database:
Run the SQL in
dbschema.sqlagainst your PostgreSQL instance to create the required tables. -
Start the server:
npm start
The server runs on
http://localhost:8080. -
Test with Postman:
Open the Postman workspace and run the collection. Use Postman Desktop (not web), as the API must be reachable on localhost.
- The Postman collection is for testing only, not official API documentation. See the
.yamlfile for that. - When running on localhost,
req.ipresolves unreliably, so the app defaults to8.8.8.8for geo-lookup — geographic logs will not be accurate in local development. - Two branches exist with different auth requirements for URL resolution (authenticated vs. unauthenticated access to
GET /url/:id).