A secure URL Shortening service built with Node.js, Express, and Prisma ORM, featuring JWT authentication, refresh tokens, and Swagger API documentation.
- β User registration and login with hashed passwords (bcrypt)
- π JWT-based authentication (access & refresh tokens)
- βοΈ Shorten long URLs into unique short codes
- π Update or delete existing URLs
- π Track number of clicks per short URL
- π§Ύ View detailed statistics for each URL
- π Automatic timestamps for creation & updates
- π Swagger documentation for all endpoints
- Node.js β JavaScript runtime
- Express.js β Web framework
- Prisma ORM β Database ORM
- SQLite / PostgreSQL / MySQL β Supported databases
- jsonwebtoken β For JWT authentication
- bcryptjs β Secure password hashing
- swagger-ui-express β API documentation
- Nodemon β Development auto-reload
project/
βββ prisma/
β βββ schema.prisma
βββ routes/
β βββ url.route.js
β βββ users.route.js
βββ middlewares/
β βββ auth.js
βββ controllers/
β βββ url.controller.js
β βββ users.controller.js
βββ utils/
β βββ utils.js
|ββ config/
β βββ swagger.js
βββ index.js
βββ package.json
git clone https://github.com/yourusername/url-shortener.git
cd url-shortenernpm installEdit your prisma/schema.prisma file to use your preferred database, then run:
npx prisma migrate dev --name initCreate a .env file in the root directory:
DATABASE_URL="file:./dev.db"
ACCESS_TOKEN_SECRET="your_access_secret_here"
REFRESH_TOKEN_SECRET="your_refresh_secret_here"
PORT=5000npx nodemon server.jsServer will start at: π http://localhost:5000
Register a new user.
Request:
{
"email": "user@example.com",
"password": "securepassword"
}Response (201):
{
"id": 1,
"email": "user@example.com",
"createdAt": "2025-10-08T12:30:00.000Z"
}Errors:
400β Invalid email or password500β Internal server error
Login and receive JWT tokens.
Request:
{
"email": "user@example.com",
"password": "securepassword"
}Response (200):
{
"message": "Login successful",
"accessToken": "your-access-token",
"refreshToken": "your-refresh-token"
}Errors:
401β Invalid credentials500β Internal server error
Generate a new access token using a valid refresh token.
Request:
{
"token": "your-refresh-token"
}Response (200):
{
"accessToken": "new-access-token"
}Errors:
401β Missing token403β Invalid or expired token
All /shorten/* routes require an Authorization header:
Authorization: Bearer <accessToken>
Create a new short URL.
Request:
{
"url": "https://example.com"
}Response (201):
{
"id": 1,
"url": "https://example.com",
"shortCode": "abc123",
}Fetch the original URL and increment its click count.
Response (200):
{
"id": 1,
"url": "https://example.com",
"shortCode": "abc123",
}Update an existing short URL.
Request:
{
"url": "https://newsite.com"
}Response (200):
{
"id": 1,
"url": "https://newsite.com",
"shortCode": "abc123",
}Delete a URL by its short code.
Response (204)
Retrieve analytics (clicks, creation date, etc.) for a URL.
Response (200):
{
"id": 1,
"url": "https://example.com",
"shortCode": "abc123",
"clicks": 10,
"createdAt": "2025-10-07T14:00:00.000Z",
"updatedAt": "2025-10-07T15:00:00.000Z"
}After starting the server, access your live Swagger docs at:
π http://localhost:5000/docs
You can:
- Test all endpoints interactively
- Use the Authorize π button to add your Bearer Token
- View all request/response schemas
model urls {
id Int @id @default(autoincrement())
url String
shortCode String @unique
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
clicks Int @default(0)
expiresAt DateTime?
}
model users {
id Int @id @default(autoincrement())
email String @unique
password String
tokens refresh_tokens[]
}
model refresh_tokens {
id Int @id @default(autoincrement())
token String @unique
userId Int
createdAt DateTime @default(now())
user users @relation(fields: [userId], references: [id], onDelete: Cascade)
}Run the project in development mode:
npx nodemon server.jsFormat your code using Prettier:
npx prettier --write .Run Prisma Studio (GUI for your DB):
npx prisma studio- Access tokens expire every 5 minutes.
- Refresh tokens last 1 day and are stored securely in your database.
- Always send your Bearer Token in the
Authorizationheader.
Solution for URL Shortening Service Project https://roadmap.sh/projects/url-shortening-service