Skip to content

Backend API for Photo Browser Application with MongoDB Atlas, built with Node.js, Express, TypeScript, and Mongoose.

Notifications You must be signed in to change notification settings

xenioushk/Photo-Browser-Backend-API

Repository files navigation

πŸ“Έ Photo Browser Backend API

Production-ready RESTful API for Photo Browser Application with JWT authentication, cloud image storage, and full CRUD operations. Built with Node.js, Express, TypeScript, MongoDB Atlas, and Cloudinary.

πŸš€ Technology Stack

Core Technologies

  • Runtime: Node.js 22 LTS
  • Framework: Express.js 4.18
  • Language: TypeScript 5.3
  • Database: MongoDB Atlas (Cloud NoSQL)
  • ODM: Mongoose 8.0

Authentication & Security

  • JWT: JSON Web Tokens for stateless authentication
  • bcryptjs: Password hashing with salt rounds
  • helmet: Security headers
  • cors: Cross-origin resource sharing
  • express-rate-limit: API rate limiting to prevent abuse
  • Zod: Runtime request validation and type-safe schemas

Image Processing & Storage

  • Cloudinary: Cloud image storage and CDN
  • Multer: Multipart form-data handling
  • Sharp: Image optimization and thumbnail generation

Development Tools

  • nodemon: Auto-reload on file changes
  • ts-node: Run TypeScript directly
  • Morgan: HTTP request logger
  • dotenv: Environment variable management

πŸ“‹ Prerequisites

  • Node.js 22 or higher
  • MongoDB Atlas account (free tier available)
  • Cloudinary account (free tier available)
  • npm or yarn package manager

πŸ› οΈ Installation

1. Install Dependencies

npm install

2. Environment Setup

Create a .env file in the root directory:

cp .env.example .env

Edit .env and add your MongoDB Atlas connection string:

PORT=5001
NODE_ENV=development
MONGODB_URI=mongodb+srv://username:[email protected]/photo-browser?retryWrites=true&w=majority
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN=7d
CLIENT_URL=http://localhost:3000
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret

3. Cloudinary Setup

  1. Create account at https://cloudinary.com
  2. Go to Dashboard to get credentials
  3. Add Cloud Name, API Key, and API Secret to .env

4. MongoDB Atlas Setup

  1. Create account at https://www.mongodb.com/cloud/atlas
  2. Create a free M0 cluster
  3. Create database user with read/write permissions
  4. Whitelist your IP address (use 0.0.0.0/0 for development)
  5. Get connection string and add to .env

5. Seed Database

npm run seed

This will populate your database with:

  • 10 users from JSONPlaceholder (password: demo123 for all)
  • 100 albums
  • 1000 photos

6. Start Development Server

npm run dev

Server will run on http://localhost:5001

πŸ“‘ API Endpoints

Health Check

GET /health - Server health status

Authentication

POST /api/auth/register       # Register new user
POST /api/auth/login          # Login user
GET  /api/auth/me             # Get current user (Protected)

Photos

GET    /api/photos?_page=1&_limit=18   # List photos with pagination
GET    /api/photos/:id                  # Get single photo
POST   /api/photos                      # Upload photo (Protected)
PUT    /api/photos/:id                  # Update photo (Protected)
DELETE /api/photos/:id                  # Delete photo (Protected)

Albums

GET    /api/albums?_page=1&_limit=18   # List albums with pagination
GET    /api/albums/:id                  # Get single album
GET    /api/albums/:albumId/photos     # Get photos by album
POST   /api/albums                      # Create album (Protected)
PUT    /api/albums/:id                  # Update album (Protected)
DELETE /api/albums/:id                  # Delete album (Protected)

Users

GET /api/users/:id                      # Get user profile

πŸ” Authentication

Register New User

POST http://localhost:5001/api/auth/register
Content-Type: application/json

{
  "name": "John Doe",
  "email": "[email protected]",
  "username": "johndoe",
  "password": "password123",
  "phone": "555-1234",          // Optional
  "website": "https://john.com" // Optional
}

Login

POST http://localhost:5001/api/auth/login
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "password123"
}

Response:

{
  "message": "Login successful",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "676c...",
    "name": "John Doe",
    "email": "[email protected]",
    "username": "johndoe"
  }
}

Using Protected Endpoints

Add the JWT token to the Authorization header:

Authorization: Bearer YOUR_JWT_TOKEN

πŸ“š API Documentation

Interactive Swagger UI

Access the interactive API documentation at:

Local Development:

http://localhost:5001/api-docs

Production:

https://your-app.onrender.com/api-docs

Features:

  • Try it out: Test all endpoints directly from the browser
  • Request/Response Examples: See example data for all endpoints
  • Authentication: Test authenticated endpoints with JWT tokens
  • Schema Definitions: View all data models and validation rules
  • Response Codes: See all possible HTTP status codes

How to Use Swagger:

  1. Open http://localhost:5001/api-docs in your browser
  2. Click on any endpoint to expand it
  3. Click "Try it out" to test the endpoint
  4. For protected endpoints:
    • First, use /api/auth/login to get a JWT token
    • Click "Authorize" button at the top
    • Enter: Bearer YOUR_TOKEN_HERE
    • Click "Authorize"
  5. Fill in the required parameters
  6. Click "Execute" to make the request
  7. View the response in the interface

πŸ“Έ Image Upload

Upload Photo

Endpoint: POST /api/photos
Authentication: Required
Content-Type: multipart/form-data

# Using HTTPie
http -f POST http://localhost:5001/api/photos \
  "Authorization:Bearer YOUR_TOKEN" \
  image@/path/to/photo.jpg \
  title="Beautiful Sunset" \
  albumId=1

# Using curl
curl -X POST http://localhost:5001/api/photos \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "image=@/path/to/photo.jpg" \
  -F "title=Beautiful Sunset" \
  -F "albumId=1"

Features:

  • Automatic image optimization (max 800x800px)
  • Thumbnail generation (150x150px)
  • Cloud storage via Cloudinary
  • Supported formats: jpeg, jpg, png, gif, webp
  • Max file size: 5MB

πŸ§ͺ Testing the API

Using HTTPie:

# Login
http POST http://localhost:5001/api/auth/login \
  [email protected] \
  password=demo123

# Save token
TOKEN="your_token_here"

# Get photos
http GET http://localhost:5001/api/photos

# Upload photo
http -f POST http://localhost:5001/api/photos \
  "Authorization:Bearer $TOKEN" \
  image@~/photo.jpg \
  title="My Photo"

# Update photo
http PUT http://localhost:5001/api/photos/1001 \
  "Authorization:Bearer $TOKEN" \
  title="Updated Title"

# Delete photo
http DELETE http://localhost:5001/api/photos/1001 \
  "Authorization:Bearer $TOKEN"

# Create album
http POST http://localhost:5001/api/albums \
  "Authorization:Bearer $TOKEN" \
  title="My Album"

# Delete album
http DELETE http://localhost:5001/api/albums/101 \
  "Authorization:Bearer $TOKEN"

Using curl:

# Health check
curl http://localhost:5001/health

# Get photos with pagination
curl "http://localhost:5001/api/photos?_page=1&_limit=18"

# Login
curl -X POST http://localhost:5001/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"demo123"}'

# Upload photo
curl -X POST http://localhost:5001/api/photos \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "[email protected]" \
  -F "title=Sunset"

πŸ“ Project Structure

photo-browser-app-backend/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ config/
β”‚   β”‚   β”œβ”€β”€ database.ts          # MongoDB connection
β”‚   β”‚   β”œβ”€β”€ cloudinary.ts        # Cloudinary configuration
β”‚   β”‚   └── swagger.ts           # Swagger/OpenAPI configuration
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ User.ts              # User schema & model
β”‚   β”‚   β”œβ”€β”€ Album.ts             # Album schema & model
β”‚   β”‚   └── Photo.ts             # Photo schema & model
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ authController.ts    # Register, login, get current user
β”‚   β”‚   β”œβ”€β”€ photoController.ts   # Photo CRUD operations
β”‚   β”‚   β”œβ”€β”€ albumController.ts   # Album CRUD operations
β”‚   β”‚   └── userController.ts    # User profile operations
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ auth.ts              # Auth routes
β”‚   β”‚   β”œβ”€β”€ photos.ts            # Photo routes
β”‚   β”‚   β”œβ”€β”€ albums.ts            # Album routes
β”‚   β”‚   └── users.ts             # User routes
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   β”œβ”€β”€ auth.ts              # JWT authentication
β”‚   β”‚   β”œβ”€β”€ errorHandler.ts      # Global error handling
β”‚   β”‚   β”œβ”€β”€ rateLimiter.ts       # Rate limiting configuration
β”‚   β”‚   β”œβ”€β”€ validateRequest.ts   # Zod validation middleware
β”‚   β”‚   └── upload.ts            # Multer file upload config
β”‚   β”œβ”€β”€ schemas/
β”‚   β”‚   β”œβ”€β”€ authSchemas.ts       # Auth validation schemas
β”‚   β”‚   β”œβ”€β”€ photoSchemas.ts      # Photo validation schemas
β”‚   β”‚   └── albumSchemas.ts      # Album validation schemas
β”‚   β”œβ”€β”€ scripts/
β”‚   β”‚   └── seedDatabase.ts      # Seed from JSONPlaceholder
β”‚   └── server.ts                # Express app entry point
β”œβ”€β”€ .env                         # Environment variables (git ignored)
β”œβ”€β”€ .env.example                 # Environment template
β”œβ”€β”€ .gitignore                   # Git ignore file
β”œβ”€β”€ package.json                 # Dependencies & scripts
β”œβ”€β”€ tsconfig.json                # TypeScript config
└── README.md                    # This file

πŸ”§ NPM Scripts

npm run dev      # Start development server with nodemon
npm run build    # Compile TypeScript to JavaScript
npm start        # Run production server
npm run seed     # Seed database with JSONPlaceholder data

πŸ›‘οΈ Rate Limiting

API rate limiting is implemented to prevent abuse and ensure fair usage:

Rate Limits:

  • General API Routes: 100 requests per 15 minutes
  • Authentication Routes (login/register): 5 requests per 15 minutes
  • Upload Routes: 10 requests per hour

Response Headers:

When rate limit is applied, the following headers are included:

RateLimit-Limit: 100
RateLimit-Remaining: 99
RateLimit-Reset: 1640000000

Rate Limit Exceeded Response:

{
  "error": "Too many requests from this IP, please try again later.",
  "retryAfter": "15 minutes"
}

Status Code: 429 Too Many Requests

βœ… Request Validation

All API endpoints validate incoming requests using Zod schemas for type-safe runtime validation.

Validation Features:

  • Authentication: Email format, password length, username constraints
  • Photos: Title length, valid URLs, numeric IDs
  • Albums: Title requirements, user associations
  • Query Parameters: Pagination limits, valid sort fields, numeric filters

Validation Error Response:

When validation fails, you'll receive a detailed error response:

{
  "error": "Validation failed",
  "details": [
    {
      "field": "email",
      "message": "Invalid email address"
    },
    {
      "field": "password",
      "message": "Password must be at least 6 characters"
    }
  ]
}

Status Code: 400 Bad Request

Example Validation Rules:

Register User:

  • name: 2-100 characters
  • email: Valid email format
  • username: 3-30 characters, alphanumeric and underscores only
  • password: 6-100 characters

Upload Photo:

  • title: 1-200 characters (required)
  • albumId: Valid numeric ID (required)

Query Parameters:

Duplicate User:

{
  "error": "User with this email or username already exists"
}

Status: 409 Conflict

Invalid Credentials:

{
  "error": "Invalid credentials"
}

Status: 401 Unauthorized

Missing Token:

{
  "error": "No token provided"
}

Status: 401 Unauthorized

Resource Not Found:

{
  "error": "Photo not found"
}

Status: 404 Not Found

  • _limit: 1-100 (default: 18)
  • _page: Positive integer (default: 1)
  • sort: One of title, createdAt, updatedAt
  • order: Either asc or desc

🌐 Connecting Frontend

Update your frontend .env file:

REACT_APP_BACKENDURL=http://localhost:5001/api

Then restart your frontend application.

✨ Features

Implemented βœ…

  • JWT Authentication - Secure user registration and login
  • Password Hashing - bcrypt with 10 salt rounds
  • Image Upload - Cloudinary integration with Sharp optimization
  • Full CRUD Operations - Create, Read, Update, Delete for photos and albums
  • Ownership Verification - Users can only modify their own content
  • Image Processing - Automatic resize (800x800) and thumbnail generation (150x150)
  • Cloud Storage - Cloudinary for image hosting and CDN delivery
  • Pagination Support - Efficient data loading with _page and _limit params
  • Database Seeding - Populate with JSONPlaceholder data
  • TypeScript - Full type safety and compile-time error checking
  • Security Headers - Helmet middleware for protection
  • CORS Configuration - Cross-origin resource sharing
  • Rate Limiting - Protection against API abuse with configurable limits
  • Request Validation - Zod schemas for runtime data validation
  • Advanced Search - Search photos and albums by title
  • Filtering - Filter by userId, albumId
  • Sorting - Sort by title, createdAt, updatedAt (asc/desc)
  • Request Logging - Morgan for HTTP request tracking
  • Rate Limiting - Protection against API abuse
  • Request Validation - Zod schemas for runtime data validation
  • Centralized Error Handling - Consistent error responses
  • Swagger Documentation - Interactive API docs at /api-docs

Security Features πŸ”’

  • Stateless Authentication - JWT tokens (7-day expiration)
  • Protected Routes - Middleware-based auth verification
  • Password Security - Never stored in plain text
  • Ownership Checks - Users can only delete/update own content
  • File Validation - Type and size restrictions on uploads
  • Cloud Cleanup - Automatic deletion from Cloudinary when photos removed
  • Cascade Protection - Albums with photos cannot be deleted

🚒 Production Deployment

Build for Production

npm run build

Deploy to Render.com

  1. Push code to GitHub
  2. Create account at https://render.com
  3. Create new Web Service
  4. Connect GitHub repository
  5. Set build command: npm install && npm run build
  6. Set start command: npm start
  7. Add environment variables from .env

Update Frontend URL

After deployment, update frontend:

REACT_APP_BACKENDURL=https://your-app.onrender.com/api

πŸ” Security Features

  • JWT Authentication: Stateless token-based auth with configurable expiration
  • bcryptjs: Secure password hashing with salt rounds
  • Helmet: Security headers for Express
  • CORS: Configured for specific origins
  • Ownership Verification: Users can only modify their own resources
  • File Validation: Type and size checks on uploads
  • Environment Variables: Sensitive data protection
  • TypeScript Strict Mode: Compile-time error prevention

🎯 Development Roadmap

Completed βœ…

  • MongoDB Atlas integration
  • User authentication (register, login)
  • JWT middleware and protected routes
  • Image upload with Cloudinary
  • Full CRUD operations for photos
  • Full CRUD operations for albums
  • Image optimization with Sharp
  • Ownership verification
  • Database seeding script

Future Enhancements πŸš€

  • Search photos by title
  • Filter by album/user
  • Sort by date/popularity
  • Refresh token implementation
  • Rate limiting
  • Request validation with Zod
  • Comprehensive error handling middleware
  • Unit and integration tests
  • API documentation with Swagger
  • Pagination metadata (total count, pages)

πŸ‘¨β€πŸ’» Author

Mahbub Alam Khan

πŸ“„ License

MIT

🌐 Deployment

Deploy to Render.com

1. Prepare for Deployment

Ensure your package.json has the correct build and start scripts (already configured):

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/server.js",
    "dev": "nodemon src/server.ts"
  }
}

2. Create Render Account

  1. Go to https://render.com
  2. Sign up with your GitHub account
  3. Connect your GitHub repository

3. Create Web Service

  1. Click "New +" β†’ "Web Service"
  2. Connect to your GitHub repository: photo-browser-app-backend
  3. Configure the service:
    • Name: photo-browser-backend
    • Environment: Node
    • Build Command: npm install && npm run build
    • Start Command: npm start
    • Instance Type: Free

4. Add Environment Variables

In Render dashboard, add all environment variables from your .env:

PORT=5000
NODE_ENV=production
MONGODB_URI=mongodb+srv://username:[email protected]/photo-browser?retryWrites=true&w=majority
JWT_SECRET=your-production-jwt-secret-here
JWT_EXPIRES_IN=7d
CLIENT_URL=https://your-frontend-domain.com
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret

Important Security Notes:

  • Use a strong, unique JWT_SECRET for production
  • Update CLIENT_URL with your deployed frontend URL
  • Ensure MongoDB Atlas Network Access allows Render's IP addresses
  • Never commit .env file to GitHub

5. Deploy

  1. Click "Create Web Service"
  2. Render will automatically build and deploy your app
  3. Your API will be available at: https://your-app-name.onrender.com

6. Verify Deployment

Test the health endpoint:

curl https://your-app-name.onrender.com/health

Expected response:

{
  "status": "OK",
  "message": "Photo Browser API is running"
}

7. Update Frontend

Update your frontend .env to point to the deployed backend:

REACT_APP_BACKENDURL=https://your-app-name.onrender.com/api

Deploy to Other Platforms

Heroku

heroku create photo-browser-backend
heroku config:set MONGODB_URI=your-mongodb-uri
heroku config:set JWT_SECRET=your-jwt-secret
# Add other environment variables
git push heroku main

Railway

  1. Go to https://railway.app
  2. Connect GitHub repository
  3. Add environment variables
  4. Deploy automatically

AWS EC2 (Advanced)

  1. Launch EC2 instance with Node.js
  2. Clone repository
  3. Install dependencies
  4. Set up PM2 for process management
  5. Configure Nginx as reverse proxy

MongoDB Atlas Production Settings

  1. Network Access:

    • Remove 0.0.0.0/0 (development wildcard)
    • Add Render/Heroku IP addresses only
  2. Database Users:

    • Use strong, unique passwords
    • Limit privileges to specific database
  3. Monitoring:

    • Enable MongoDB Atlas monitoring
    • Set up alerts for connection issues

Continuous Deployment

Render automatically deploys when you push to main branch:

git add .
git commit -m "Update feature"
git push origin main

Render will:

  1. Detect the push
  2. Run build command
  3. Deploy new version
  4. Zero downtime deployment

🀝 Contributing

Contributions, issues, and feature requests are welcome!

πŸ“ž Support & Resources


Created: December 29, 2025
Last Updated: December 29, 2025

About

Backend API for Photo Browser Application with MongoDB Atlas, built with Node.js, Express, TypeScript, and Mongoose.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published