Skip to content

A sophisticated Node.js web API for file storage with S3-like functionality, MySQL metadata storage, and JWT authentication.

Notifications You must be signed in to change notification settings

MRsuffixx/LocalStorageApi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Local Storage API

A sophisticated Node.js web API for file storage with S3-like functionality, MySQL metadata storage, and JWT authentication.

Features

  • File Management

    • Upload files (images, documents, archives)
    • Chunked uploads for large files
    • Download and stream files
    • Delete files
    • File metadata management
  • User Authentication

    • JWT-based authentication
    • User registration and login
    • Password hashing with Argon2
    • Token refresh mechanism
  • Security

    • Rate limiting
    • CORS protection
    • Helmet security headers
    • Path traversal prevention
    • Input validation and sanitization
  • Storage

    • Local file storage with organized directory structure
    • MySQL database for metadata
    • User storage quotas
    • File checksums for integrity

Tech Stack

  • Runtime: Node.js (v18+)
  • Framework: Express.js
  • Database: MySQL with Sequelize ORM
  • Authentication: JWT (jsonwebtoken)
  • Password Hashing: Argon2
  • File Upload: Multer
  • Validation: express-validator
  • Security: Helmet, CORS, express-rate-limit

Project Structure

LocalStorageApi/
├── config/
│   ├── app.js          # Application configuration
│   └── database.js     # Database configuration
├── middleware/
│   ├── auth.js         # Authentication middleware
│   ├── errorHandler.js # Error handling
│   ├── security.js     # Security middleware
│   ├── validation.js   # Request validation
│   └── index.js        # Middleware exports
├── models/
│   ├── User.js         # User model
│   ├── File.js         # File model
│   ├── ChunkedUpload.js # Chunked upload model
│   └── index.js        # Model associations
├── routes/
│   ├── auth.js         # Authentication routes
│   ├── files.js        # File routes
│   └── index.js        # Route exports
├── services/
│   └── uploadService.js # File upload service
├── scripts/
│   ├── syncDatabase.js # Database sync script
│   └── seedDatabase.js # Database seed script
├── uploads/            # File storage directory
├── .env                # Environment variables
├── .env.example        # Example environment file
├── package.json        # Dependencies
├── server.js           # Main server file
└── README.md           # This file

Installation

Prerequisites

  • Node.js v18 or higher
  • MySQL 8.0 or higher
  • npm or yarn

Setup

  1. Clone the repository

    cd LocalStorageApi
  2. Install dependencies

    npm install
  3. Configure environment

    # Copy example env file
    cp .env.example .env
    
    # Edit .env with your settings
    # Make sure to set:
    # - DB_PASSWORD (your MySQL password)
    # - JWT_SECRET (generate a secure secret)
  4. Create MySQL database

    CREATE DATABASE local_storage_api;
  5. Sync database tables

    npm run db:sync
  6. Seed sample data (optional)

    npm run db:seed
  7. Start the server

    # Development mode (with auto-reload)
    npm run dev
    
    # Production mode
    npm start

API Documentation

Base URL

http://localhost:3001/api

Authentication

All protected endpoints require a Bearer token in the Authorization header:

Authorization: Bearer <your_jwt_token>

Auth Endpoints

Register User

POST /api/auth/register
Content-Type: application/json

{
  "email": "user@example.com",
  "username": "johndoe",
  "password": "SecurePass@123",
  "confirmPassword": "SecurePass@123",
  "firstName": "John",
  "lastName": "Doe"
}

Response:

{
  "success": true,
  "message": "Registration successful",
  "data": {
    "user": {
      "id": "uuid",
      "email": "user@example.com",
      "username": "johndoe",
      "firstName": "John",
      "lastName": "Doe",
      "role": "user",
      "storageUsed": 0,
      "storageLimit": 5368709120
    },
    "tokens": {
      "accessToken": "jwt_token",
      "refreshToken": "refresh_token",
      "expiresIn": "7d"
    }
  }
}

Login

POST /api/auth/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "SecurePass@123"
}

Get Current User

GET /api/auth/me
Authorization: Bearer <token>

Update Profile

PUT /api/auth/me
Authorization: Bearer <token>
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Smith",
  "username": "johnsmith"
}

Change Password

POST /api/auth/change-password
Authorization: Bearer <token>
Content-Type: application/json

{
  "currentPassword": "OldPass@123",
  "newPassword": "NewPass@456",
  "confirmNewPassword": "NewPass@456"
}

Refresh Token

POST /api/auth/refresh
Content-Type: application/json

{
  "refreshToken": "your_refresh_token"
}

Logout

POST /api/auth/logout
Authorization: Bearer <token>

File Endpoints

Upload File

POST /api/files/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data

file: <binary>
description: "My file description"
tags: ["tag1", "tag2"]
isPublic: false

Response:

{
  "success": true,
  "message": "File uploaded successfully",
  "data": {
    "file": {
      "id": "uuid",
      "originalName": "document.pdf",
      "mimeType": "application/pdf",
      "size": 1024000,
      "formattedSize": "1.00 MB",
      "url": "http://localhost:3001/api/files/uuid",
      "downloadUrl": "http://localhost:3001/api/files/uuid/download",
      "isPublic": false,
      "description": "My file description",
      "tags": ["tag1", "tag2"],
      "uploadedAt": "2024-01-01T00:00:00.000Z"
    }
  }
}

List Files

GET /api/files?page=1&limit=20&sortBy=created_at&sortOrder=desc&search=document
Authorization: Bearer <token>

Query Parameters:

  • page - Page number (default: 1)
  • limit - Items per page (default: 20, max: 100)
  • sortBy - Sort field: created_at, original_name, size, mime_type
  • sortOrder - Sort direction: asc, desc
  • mimeType - Filter by MIME type prefix (e.g., "image/")
  • search - Search in filename

Get File Info

GET /api/files/:fileId
Authorization: Bearer <token>

Download File

GET /api/files/:fileId/download
Authorization: Bearer <token>

View File (Inline)

GET /api/files/:fileId/view
Authorization: Bearer <token>

Update File Metadata

PUT /api/files/:fileId
Authorization: Bearer <token>
Content-Type: application/json

{
  "description": "Updated description",
  "tags": ["new-tag"],
  "isPublic": true
}

Delete File

DELETE /api/files/:fileId
Authorization: Bearer <token>

Get Storage Statistics

GET /api/files/stats/summary
Authorization: Bearer <token>

Chunked Upload Endpoints

For large files, use chunked uploads:

Initialize Chunked Upload

POST /api/files/chunked/init
Authorization: Bearer <token>
Content-Type: application/json

{
  "fileName": "large-video.mp4",
  "fileSize": 1073741824,
  "mimeType": "video/mp4",
  "totalChunks": 205
}

Upload Chunk

POST /api/files/chunked/:uploadId/chunk
Authorization: Bearer <token>
Content-Type: multipart/form-data
X-Chunk-Number: 0

chunk: <binary>

Complete Chunked Upload

POST /api/files/chunked/:uploadId/complete
Authorization: Bearer <token>
Content-Type: application/json

{
  "description": "My large video",
  "tags": ["video"],
  "isPublic": false
}

Get Upload Status

GET /api/files/chunked/:uploadId/status
Authorization: Bearer <token>

Cancel Upload

DELETE /api/files/chunked/:uploadId
Authorization: Bearer <token>

Configuration

Environment Variables

Variable Description Default
NODE_ENV Environment (development/production) development
PORT Server port 3000
HOST Server host localhost
DB_HOST MySQL host localhost
DB_PORT MySQL port 3306
DB_NAME Database name local_storage_api
DB_USER Database user root
DB_PASSWORD Database password -
JWT_SECRET JWT signing secret -
JWT_EXPIRES_IN Access token expiry 7d
UPLOAD_DIR Upload directory ./uploads
MAX_FILE_SIZE Max file size (bytes) 104857600 (100MB)
ALLOWED_FILE_TYPES Allowed MIME types image/*,application/pdf,...
RATE_LIMIT_WINDOW_MS Rate limit window 900000 (15min)
RATE_LIMIT_MAX_REQUESTS Max requests per window 100

Allowed File Types

Default allowed MIME types:

  • Images: jpeg, png, gif, webp
  • Documents: pdf, doc, docx, txt
  • Archives: zip

Modify ALLOWED_FILE_TYPES in .env to customize.

Security Considerations

  1. JWT Secret: Generate a strong secret for production:

    node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
  2. HTTPS: Use HTTPS in production (configure via reverse proxy)

  3. Rate Limiting: Adjust limits based on your needs

  4. File Validation: Files are validated by MIME type and size

  5. Path Traversal: All file paths are sanitized

  6. Password Requirements:

    • Minimum 8 characters
    • At least one uppercase letter
    • At least one lowercase letter
    • At least one number
    • At least one special character

Error Handling

All errors follow a consistent format:

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable message",
    "details": [] // Optional validation details
  }
}

Common error codes:

  • UNAUTHORIZED - Authentication required
  • FORBIDDEN - Access denied
  • NOT_FOUND - Resource not found
  • VALIDATION_ERROR - Request validation failed
  • RATE_LIMIT_EXCEEDED - Too many requests
  • PAYLOAD_TOO_LARGE - File too large
  • UNSUPPORTED_MEDIA_TYPE - File type not allowed

Development

# Run in development mode with auto-reload
npm run dev

# Sync database (creates/updates tables)
npm run db:sync

# Seed database with sample data
npm run db:seed

# Force sync (drops all tables - DANGEROUS)
npm run db:sync -- --force

License

MIT License

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a Pull Request

About

A sophisticated Node.js web API for file storage with S3-like functionality, MySQL metadata storage, and JWT authentication.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published