DEV Community

Ameh Mathias Ejeh
Ameh Mathias Ejeh

Posted on

Todo List Backend API

A comprehensive, production-ready REST API for a Todo List application built with Node.js, Express, MongoDB, and ECMAScript Modules (ESM). Features include JWT authentication, task management with advanced filtering, email notifications, and user profile management.

Features

  • JWT-based Authentication - Secure user authentication with token-based sessions
  • Complete Task Management - CRUD operations with advanced filtering and search
  • Email Notifications - Task creation confirmations and daily reminders
  • User Profile Management - Update name, email, and password
  • Advanced Filtering - Filter tasks by completion status, priority, due date, and search terms
  • Pagination - Efficient handling of large task lists
  • Security Features - Rate limiting, CORS, helmet protection
  • Input Validation - Comprehensive request validation using express-validator
  • RESTful Design - Clean, intuitive API endpoints

Technology Stack

  • Runtime: Node.js with ECMAScript Modules (ESM)
  • Framework: Express.js
  • Database: MongoDB with Mongoose ODM
  • Authentication: JWT (JSON Web Tokens)
  • Password Hashing: bcryptjs
  • Email Service: Nodemailer
  • Validation: express-validator
  • Scheduling: node-cron (for daily reminders)
  • Security: cors, express-rate-limit

Project Structure

todo-backend-api/
├── server.js                 # Main server file
├── package.json              # Dependencies and scripts
├── .env                      # Environment variables
├── README.md                 # API documentation
├── controllers/
│   ├── authController.js     # Authentication logic
│   └── taskController.js     # Task management logic
├── models/
│   ├── User.js              # User data model
│   └── Task.js              # Task data model
├── middleware/
│   ├── authMiddleware.js    # JWT authentication middleware
│   ├── errorMiddleware.js   # Global error handling
│   └── validationMiddleware.js # Input validation rules
├── routes/
│   ├── authRoutes.js        # Authentication routes
│   └── taskRoutes.js        # Task management routes
├── services/
│   └── emailService.js      # Email notification service
└── utils/
    ├── generateToken.js     # JWT token generation
    └── responseHandler.js   # Standardized API responses
Enter fullscreen mode Exit fullscreen mode

The API will be available at http://todo-list-application.up.railway.app

API Documentation

Base URL

http://todo-list-application.up.railway.app/api
Enter fullscreen mode Exit fullscreen mode

Response Format

All API responses follow this standardized format:

{
  "success": true,
  "message": "Operation completed successfully",
  "data": {
    // Response data (when applicable)
  }
}
Enter fullscreen mode Exit fullscreen mode

Authentication Endpoints

Register User

Create a new user account.
Endpoint: POST /api/register
Request Body:

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "password123"
}
Enter fullscreen mode Exit fullscreen mode

Success Response (201):

{
  "success": true,
  "message": "User registered successfully",
  "data": {
    "user": {
      "id": "60f7b3b3b3b3b3b3b3b3b3b3",
      "name": "John Doe",
      "email": "john@example.com",
      "createdAt": "2023-11-20T10:30:00.000Z"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
Enter fullscreen mode Exit fullscreen mode

Error Response (400):

{
  "success": false,
  "message": "User with this email already exists"
}
Enter fullscreen mode Exit fullscreen mode

Login User

Authenticate an existing user.
Endpoint: POST /api/login
Request Body:

{
  "email": "john@example.com",
  "password": "password123"
}
Enter fullscreen mode Exit fullscreen mode

Success Response (200):

{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": {
      "id": "60f7b3b3b3b3b3b3b3b3b3b3",
      "name": "John Doe",
      "email": "john@example.com",
      "createdAt": "2023-11-20T10:30:00.000Z"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
Enter fullscreen mode Exit fullscreen mode

Update Profile

Update user's profile information.
Endpoint: PUT /api/profile
Authentication: Required (Bearer Token)
Request Body:

{
  "name": "John Smith",
  "email": "johnsmith@example.com",
  "password": "newpassword123"
}
Enter fullscreen mode Exit fullscreen mode

Success Response (200):

{
  "success": true,
  "message": "Profile updated successfully",
  "data": {
    "user": {
      "id": "60f7b3b3b3b3b3b3b3b3b3b3",
      "name": "John Smith",
      "email": "johnsmith@example.com",
      "updatedAt": "2023-11-20T11:00:00.000Z"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Task Management Endpoints

Create Task

Create a new task and send confirmation email.
Endpoint: POST /api/tasks
Authentication: Required (Bearer Token)
Request Body:

{
  "title": "Complete project documentation",
  "description": "Write comprehensive API documentation for the todo app",
  "dueDate": "2023-11-25T15:30:00.000Z",
  "priority": "High"
}
Enter fullscreen mode Exit fullscreen mode

Success Response (201):

{
  "success": true,
  "message": "Task created successfully",
  "data": {
    "task": {
      "_id": "60f7b3b3b3b3b3b3b3b3b3b3",
      "title": "Complete project documentation",
      "description": "Write comprehensive API documentation for the todo app",
      "dueDate": "2023-11-25T15:30:00.000Z",
      "priority": "High",
      "isCompleted": false,
      "userId": "60f7b3b3b3b3b3b3b3b3b3b3",
      "createdAt": "2023-11-20T10:30:00.000Z",
      "updatedAt": "2023-11-20T10:30:00.000Z"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Get All Tasks

Retrieve tasks with optional filtering, searching, and pagination.
Endpoint: GET /api/tasks
Authentication: Required (Bearer Token)
Query Parameters:

  • isCompleted (boolean): Filter by completion status
  • priority (string): Filter by priority (Low, Medium, High)
  • dueDate (string): Filter by due date (YYYY-MM-DD format)
  • search (string): Search in title and description
  • page (integer): Page number for pagination (default: 1)
  • limit (integer): Number of items per page (default: 10, max: 100)
  • sortBy (string): Sort field (default: createdAt)
  • sortOrder (string): Sort order - asc or desc (default: desc)

Example Request:

GET /api/tasks?isCompleted=false&priority=High&page=1&limit=5&search=project
Enter fullscreen mode Exit fullscreen mode

Success Response (200):

{
  "success": true,
  "message": "Tasks retrieved successfully",
  "data": {
    "tasks": [
      {
        "_id": "60f7b3b3b3b3b3b3b3b3b3b3",
        "title": "Complete project documentation",
        "description": "Write comprehensive API documentation",
        "dueDate": "2023-11-25T15:30:00.000Z",
        "priority": "High",
        "isCompleted": false,
        "userId": "60f7b3b3b3b3b3b3b3b3b3b3",
        "createdAt": "2023-11-20T10:30:00.000Z",
        "updatedAt": "2023-11-20T10:30:00.000Z"
      }
    ],
    "pagination": {
      "currentPage": 1,
      "totalPages": 3,
      "totalTasks": 15,
      "hasNextPage": true,
      "hasPrevPage": false,
      "limit": 5
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Get Single Task

Retrieve a specific task by ID.
Endpoint: GET /api/tasks/:id
Authentication: Required (Bearer Token)
Success Response (200):

{
  "success": true,
  "message": "Task retrieved successfully",
  "data": {
    "task": {
      "_id": "60f7b3b3b3b3b3b3b3b3b3b3",
      "title": "Complete project documentation",
      "description": "Write comprehensive API documentation",
      "dueDate": "2023-11-25T15:30:00.000Z",
      "priority": "High",
      "isCompleted": false,
      "userId": "60f7b3b3b3b3b3b3b3b3b3b3",
      "createdAt": "2023-11-20T10:30:00.000Z",
      "updatedAt": "2023-11-20T10:30:00.000Z"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Update Task

Update an existing task.
Endpoint: PUT /api/tasks/:id
Authentication: Required (Bearer Token)
Request Body:

{
  "title": "Updated task title",
  "description": "Updated description",
  "dueDate": "2023-11-26T15:30:00.000Z",
  "priority": "Medium",
  "isCompleted": true
}
Enter fullscreen mode Exit fullscreen mode

Success Response (200):

{
  "success": true,
  "message": "Task updated successfully",
  "data": {
    "task": {
      "_id": "60f7b3b3b3b3b3b3b3b3b3b3",
      "title": "Updated task title",
      "description": "Updated description",
      "dueDate": "2023-11-26T15:30:00.000Z",
      "priority": "Medium",
      "isCompleted": true,
      "completedAt": "2023-11-20T12:00:00.000Z",
      "userId": "60f7b3b3b3b3b3b3b3b3b3b3",
      "createdAt": "2023-11-20T10:30:00.000Z",
      "updatedAt": "2023-11-20T12:00:00.000Z"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Delete Task

Delete a specific task.
Endpoint: DELETE /api/tasks/:id
Authentication: Required (Bearer Token)
Success Response (200):

{
  "success": true,
  "message": "Task deleted successfully"
}
Enter fullscreen mode Exit fullscreen mode

Email Notifications

Task Creation Confirmation

Automatically sent when a new task is created. Contains task details and encouragement message.

Daily Reminders

Automatically sent at 9:00 AM UTC to users who have tasks due the next day. Uses node-cronfor scheduling.

Email Content Includes:

  • List of tasks due tomorrow
  • Task titles, descriptions, and priorities
  • Color-coded priority indicators
  • Professional HTML formatting

Authentication

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

Authorization: Bearer <your-jwt-token>
Enter fullscreen mode Exit fullscreen mode

Token Structure:

  • Expires in 7 days (configurable)
  • Contains user ID in payload
  • Signed with JWT_SECRET from environment variables

Error Handling

Common Error Responses

Validation Error (400):

{
  "success": false,
  "message": "Title must be between 1 and 100 characters"
}
Enter fullscreen mode Exit fullscreen mode

Authentication Error (401):

{
  "success": false,
  "message": "Access denied. No token provided."
}
Enter fullscreen mode Exit fullscreen mode

Not Found Error (404):

{
  "success": false,
  "message": "Task not found"
}
Enter fullscreen mode Exit fullscreen mode

Server Error (500):

{
  "success": false,
  "message": "Server error during task creation"
}
Enter fullscreen mode Exit fullscreen mode

Input Validation

User Registration

  • name: 2-50 characters, trimmed
  • email: Valid email format, lowercase, unique
  • password: Minimum 6 characters

Task Creation/Update

  • title: 1-100 characters, required, trimmed
  • description: Optional, max 500 characters, trimmed
  • priority: Must be "Low", "Medium", or "High"
  • dueDate: Must be valid ISO 8601 date, future dates only
  • isCompleted: Boolean value

Security Features

Rate Limiting

  • 100 requests per 15 minutes per IP address
  • Applied to all /api/* routes

Password Security

  • Hashed using bcryptjs with salt rounds of 12
  • Never returned in API responses
  • Comparison using secure bcrypt.compare()

CORS Protection

  • Configurable allowed origins
  • Credentials support enabled

Database Schema

User Collection

{
  _id: ObjectId,
  name: String (required, 2-50 chars),
  email: String (required, unique, lowercase),
  password: String (required, hashed, min 6 chars),
  createdAt: Date,
  updatedAt: Date
}
Enter fullscreen mode Exit fullscreen mode

Task Collection

{
  _id: ObjectId,
  title: String (required, 1-100 chars),
  description: String (optional, max 500 chars),
  dueDate: Date (optional, future dates only),
  priority: String (enum: Low/Medium/High, default: Medium),
  isCompleted: Boolean (default: false),
  completedAt: Date (set when completed),
  userId: ObjectId (required, references User),
  createdAt: Date,
  updatedAt: Date
}
Enter fullscreen mode Exit fullscreen mode

Database Indexes

  • userId + createdAt (compound index for efficient task queries)
  • userId + isCompleted (for filtering completed tasks)
  • userId + priority (for priority filtering)
  • dueDate (for reminder email queries)

Deployment

Environment Variables for Production

NODE_ENV=production
PORT=3000
MONGODB_URI=mongodb://your-production-mongodb-uri
JWT_SECRET=your-very-secure-production-jwt-secret
JWT_EXPIRE=7d

# Production Email Service (replace with your SMTP provider)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-specific-password
EMAIL_FROM=noreply@yourdomain.com

# Frontend URL for CORS
FRONTEND_URL=https://your-frontend-domain.com
Enter fullscreen mode Exit fullscreen mode

Top comments (0)