A RESTful API for the InterviewPrep platform - a community-sourced interview question bank where students can anonymously submit and browse interview questions from real company interviews.
Note: This is the backend repository. The frontend React application is maintained in a separate repository.
- Project Overview
- Tech Stack
- Features
- Project Structure
- Getting Started
- Environment Setup
- API Documentation
- Database Models
- Authentication
- Contributing
- Development Guidelines
- Testing
InterviewPrep Backend is a Node.js + Express API that provides endpoints for user authentication, question management, searching, filtering, and upvoting. This is a Hacktoberfest 2025 project with detailed TODO comments throughout the codebase for contributors to implement features.
- User registration and authentication with JWT
- CRUD operations for interview questions
- Search and advanced filtering (company, topic, role, difficulty)
- Upvote system for questions
- Role-based access control (user/admin)
- Input validation and error handling
- Rate limiting for security
The frontend React application (separate repository) consumes this API:
- Frontend makes HTTP requests to these endpoints
- API responds with JSON data
- JWT tokens are used for authentication
- CORS is configured to allow frontend access
- Node.js - JavaScript runtime
- Express.js - Web framework
- MongoDB - NoSQL database
- Mongoose - MongoDB ODM
- JWT - Authentication tokens
- bcryptjs - Password hashing
- express-validator - Input validation
- express-rate-limit - Rate limiting
- Project structure and boilerplate
- Route definitions with TODO comments
- Validation middleware chains
- Error handling setup
- Rate limiting configuration
- Model schemas with method placeholders
- Database connection logic
- User authentication (register, login)
- Password hashing and JWT generation
- Question CRUD operations
- Search and filtering logic
- Upvote system
- Authorization middleware
- Category endpoints
backend/
βββ config/
β βββ database.js # MongoDB connection [TODO]
β
βββ controllers/
β βββ authController.js # Auth logic [TODO]
β βββ questionController.js # Question CRUD [TODO]
β
βββ middleware/
β βββ authMiddleware.js # JWT auth [TODO]
β βββ errorMiddleware.js # Error handling [TODO]
β βββ validationMiddleware.js # Validation chains [PARTIAL]
β
βββ models/
β βββ User.js # User schema [TODO]
β βββ Question.js # Question schema [TODO]
β
βββ routes/
β βββ authRoutes.js # Auth endpoints [TODO]
β βββ questionRoutes.js # Question endpoints [TODO]
β βββ categoryRoutes.js # Category endpoints [TODO]
β
βββ utils/
β βββ rateLimiter.js # Rate limiting [COMPLETE]
β
βββ .env.example # Environment template
βββ .eslintrc.json # ESLint config
βββ .prettierrc.json # Prettier config
βββ package.json # Dependencies
βββ server.js # Entry point [TODO]
- Node.js v16 or higher
- MongoDB (local installation or MongoDB Atlas account)
- npm or yarn
- Git
- Clone the repository
git clone <backend-repo-url>
cd interviewprep-backend- Install dependencies
npm install- Setup environment variables
cp .env.example .envEdit .env file with your configuration:
PORT=5000
NODE_ENV=development
MONGODB_URI=mongodb://localhost:27017/interviewprep
JWT_SECRET=your_super_secret_jwt_key_here
JWT_EXPIRE=7d
FRONTEND_URL=http://localhost:5173- Start MongoDB
For local MongoDB:
mongodFor MongoDB Atlas, use the connection string in .env.
- Start the development server
npm run devThe API will be available at: http://localhost:5000
Create a .env file in the root directory:
# Server Configuration
PORT=5000
NODE_ENV=development
# Database Configuration
MONGODB_URI=mongodb://localhost:27017/interviewprep
# For MongoDB Atlas:
# MONGODB_URI=mongodb+srv://<username>:<password>@cluster.mongodb.net/interviewprep
# JWT Configuration
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production
JWT_EXPIRE=7d
# CORS Configuration
FRONTEND_URL=http://localhost:5173Important:
- Use a strong
JWT_SECRETin production - Never commit
.envfile to Git - Update
FRONTEND_URLto match your frontend URL
Option 1: Local MongoDB
# Install MongoDB
# macOS: brew install mongodb-community
# Ubuntu: sudo apt-get install mongodb
# Start MongoDB service
mongodOption 2: MongoDB Atlas (Cloud)
- Create account at mongodb.com/cloud/atlas
- Create a cluster
- Get connection string
- Whitelist your IP address
- Add connection string to
.env
http://localhost:5000/api
POST /api/auth/register
Content-Type: application/json
{
```json
{
"name": "John Doe",
"email": "[email protected]",
"password": "password123"
}Response:
{
"success": true,
"token": "jwt_token_here",
"user": {
"id": "user_id",
"name": "John Doe",
"email": "[email protected]",
"role": "user"
}
}POST /api/auth/login
Body:
{
"email": "[email protected]",
"password": "password123"
}Response:
{
"success": true,
"token": "jwt_token_here",
"user": {
"id": "user_id",
"name": "John Doe",
"email": "[email protected]",
"role": "user"
}
}GET /api/auth/profile
Authorization: Bearer <token>
Response:
{
"success": true,
"user": {
"id": "user_id",
"name": "John Doe",
"email": "[email protected]",
"role": "user",
"createdAt": "2024-01-01T00:00:00.000Z"
}
}GET /api/questions
Query Parameters:
company- Filter by companytopic- Filter by topicrole- Filter by roledifficulty- Filter by difficulty (Easy/Medium/Hard)sort- Sort by (latest/oldest/upvotes)page- Page number (default: 1)limit- Results per page (default: 10)fromDate- Filter from datetoDate- Filter to date
Response:
{
"success": true,
"count": 50,
"pagination": {
"currentPage": 1,
"totalPages": 5,
"totalQuestions": 50
},
"questions": [
{
"id": "question_id",
"questionText": "Explain closures in JavaScript",
"company": "Google",
"topic": "JavaScript",
"role": "Frontend Developer",
"difficulty": "Medium",
"upvoteCount": 15,
"createdAt": "2024-01-01T00:00:00.000Z"
}
]
}GET /api/questions/:id
POST /api/questions
Authorization: Bearer <token>
Body:
{
"questionText": "Explain closures in JavaScript",
"company": "Google",
"topic": "JavaScript",
"role": "Frontend Developer",
"difficulty": "Medium"
}PUT /api/questions/:id
Authorization: Bearer <token>
Only owner or admin can update.
DELETE /api/questions/:id
Authorization: Bearer <token>
Only owner or admin can delete.
POST /api/questions/:id/upvote
Authorization: Bearer <token>
GET /api/questions/:id/upvotes
GET /api/questions/search?q=keyword
GET /api/categories
Returns unique topics, companies, and roles.
Response:
{
"success": true,
"categories": {
"topics": ["JavaScript", "React", "Node.js"],
"companies": ["Google", "Microsoft", "Amazon"],
"roles": ["Frontend Developer", "Backend Developer", "SDE"]
}
}The API uses JWT (JSON Web Tokens) for authentication.
- User registers or logs in
- Server generates JWT token
- Client stores token (localStorage/sessionStorage)
- Client sends token in Authorization header for protected routes
- Server verifies token and grants/denies access
Protected routes require the Authorization header:
Authorization: Bearer <your_jwt_token>
Tokens expire based on JWT_EXPIRE environment variable. Users need to login again after expiration.
{
name: String, // User's full name
email: String, // Unique email
password: String, // Hashed password
role: String, // 'user' or 'admin'
createdAt: Date, // Registration date
updatedAt: Date // Last update
}Methods:
comparePassword(plainPassword)- Verify passwordgenerateAuthToken()- Generate JWT token
{
questionText: String, // The interview question
company: String, // Company name
topic: String, // Technical topic
role: String, // Job role
difficulty: String, // Easy/Medium/Hard
upvotedBy: [ObjectId], // Array of user IDs who upvoted
upvoteCount: Number, // Total upvotes
submittedBy: ObjectId, // User who submitted (optional/anonymous)
createdAt: Date, // Submission date
updatedAt: Date // Last update
}Methods:
addUpvote(userId)- Toggle upvote for user
protect- Verifies JWT token and attaches user to requestauthorize(...roles)- Restricts access to specific roles
Usage:
router.get('/admin', protect, authorize('admin'), controller);Provides validation chains for:
- User registration
- User login
- Question creation
- Question updates
notFound- Handles 404 errorserrorHandler- Centralized error handling with proper status codes
npm run dev # Start with nodemon (auto-reload)
npm start # Start production server
npm run lint # Run ESLint
npm run format # Format code with PrettierThe project uses:
- ESLint for code linting
- Prettier for code formatting
Configuration files:
.eslintrc.json.prettierrc.json
- Create controller in
controllers/ - Create route file in
routes/ - Import and use in
server.js
Example:
// routes/newRoute.js
import express from 'express';
import { myController } from '../controllers/myController.js';
const router = express.Router();
router.get('/', myController);
export default router;
// server.js
import newRoutes from './routes/newRoute.js';
app.use('/api/new', newRoutes);Register:
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"[email protected]","password":"password123"}'Login:
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password123"}'Get Questions:
curl http://localhost:5000/api/questionsCreate Question (with token):
curl -X POST http://localhost:5000/api/questions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{
"questionText": "Explain promises in JavaScript",
"company": "Microsoft",
"topic": "JavaScript",
"role": "SDE",
"difficulty": "Medium"
}'Recommended tools:
- Postman - Full-featured API testing
- Thunder Client - VS Code extension
- Insomnia - REST client
- curl - Command-line tool
- Passwords are hashed with bcrypt (10 salt rounds)
- JWT tokens are signed with secret key
- Input validation on all routes
- Rate limiting on sensitive endpoints
- CORS configured for specific origin
- Error messages don't leak sensitive information
- MongoDB injection protection via Mongoose
The API uses consistent error responses:
{
"success": false,
"message": "Error message here",
"error": "Detailed error (development only)"
}HTTP Status Codes:
200- Success201- Created400- Bad Request (validation errors)401- Unauthorized (invalid/missing token)403- Forbidden (insufficient permissions)404- Not Found500- Internal Server Error
Rate limits are configured in utils/rateLimiter.js:
- Auth routes: 5 requests per 15 minutes per IP
- General routes: 100 requests per 15 minutes per IP
This is a Hacktoberfest 2024 project! We welcome contributions from developers of all skill levels.
-
Find an Issue
- Browse open issues
- Look for
hacktoberfest,good-first-issue, orhelp-wantedlabels - Comment to get assigned
-
Fork and Clone
git clone https://github.com/your-username/interviewprep-backend.git
cd interviewprep-backend- Create a Branch
git checkout -b feature/your-feature-name-
Follow TODO Comments
- Every file has detailed TODO comments
- Read the instructions carefully
- Follow existing code patterns
-
Test Your Changes
- Test endpoints with Postman/curl
- Verify error handling
- Check console for errors
-
Commit and Push
git add .
git commit -m "feat: implement user authentication"
git push origin feature/your-feature-nameCommit Message Convention:
feat:- New featurefix:- Bug fixdocs:- Documentationrefactor:- Code refactoringtest:- Tests
- Create Pull Request
- Link related issue
- Describe changes
- Wait for review
π’ Easy (Beginner-Friendly)
- Complete database connection
- Implement validation rules
- Add error messages
- Write documentation
π‘ Medium
- Implement authentication controllers
- Build question CRUD operations
- Add search functionality
- Implement filtering logic
π΄ Hard
- Advanced search with full-text
- Caching with Redis
- Real-time features
- Analytics endpoints
- Use ES6+ features
- Use
const/let, avoidvar - Meaningful variable names
- Keep functions small and focused
- Add comments for complex logic
- One controller per resource
- Group related routes together
- Keep middleware reusable
- Separate business logic from routes
Always use try-catch in async functions:
export const myController = async (req, res, next) => {
try {
// Your logic here
} catch (error) {
next(error);
}
};- Never commit
.envor secrets - Hash passwords with bcrypt
- Validate all user inputs
- Use rate limiting
- Set proper CORS configuration
- Sanitize database queries
npm run dev # Start with nodemon (auto-reload)
npm start # Start production server
npm run lint # Run ESLint
npm run format # Format with Prettier- User registration works
- User login returns token
- Protected routes require token
- Invalid token returns 401
- Questions can be created
- Questions can be filtered
- Search returns relevant results
- Upvote toggles correctly
- Error handling works
- Rate limiting prevents abuse
Error: connect ECONNREFUSED 127.0.0.1:27017
Solution: Ensure MongoDB is running (mongod)
Error: listen EADDRINUSE: address already in use :::5000
Solution:
# Find process
lsof -i :5000
# Kill it
kill -9 <PID>Solution:
- Check
JWT_SECRETin.env - Ensure token format:
Bearer <token> - Verify token hasn't expired
- Frontend Repository: Frontend Repo
- Documentation for Endpoints[API Routes]: Docs
For questions or issues:
- Check existing issues
- Read TODO comments in code
- Create new issue with details
- Join community discussions
- π§ Email: [email protected]
π‘ Happy Coding & Keep Contributing! π
#Hacktoberfest2025 #OpenSource #InterviewPrep