A professional, production-ready RESTful Todo API built with TypeScript and Express. This application demonstrates best practices in Node.js development including proper project structure, error handling, validation, testing, and code quality tools.
/api-docstodo-api/
├── src/
│ ├── config/ # Configuration files
│ │ └── env.config.ts
│ ├── controllers/ # Request handlers
│ │ └── todo.controller.ts
│ ├── middleware/ # Express middleware
│ │ ├── error.middleware.ts
│ │ ├── logger.middleware.ts
│ │ └── validation.middleware.ts
│ ├── models/ # Data models
│ │ └── todo.model.ts
│ ├── routes/ # API routes
│ │ ├── index.ts
│ │ └── todo.routes.ts
│ ├── types/ # TypeScript type definitions
│ │ ├── express.types.ts
│ │ └── todo.types.ts
│ ├── utils/ # Utility functions
│ │ └── logger.ts
│ ├── app.ts # Express app configuration
│ └── server.ts # Server entry point
├── tests/ # Test files
│ └── todo.test.ts
├── .env.example # Environment variables template
├── .eslintrc.json # ESLint configuration
├── .prettierrc # Prettier configuration
├── jest.config.js # Jest configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Project dependencies and scripts
Clone the repository
git clone https://github.com/UNC-GDSC/ToDo-APIs.git
cd ToDo-APIs
Install dependencies
npm install
Set up environment variables
cp .env.example .env
Edit .env file with your configuration:
NODE_ENV=development
PORT=3000
API_PREFIX=/api
Run the application with auto-reload on file changes:
npm run dev
Build and run the compiled application:
npm run build
npm start
The server will start on http://localhost:3000 (or your configured PORT).
Run the application using Docker:
# Build the Docker image
docker build -t todo-api .
# Run the container
docker run -p 3000:3000 --env-file .env todo-api
# Or use Docker Compose
docker-compose up
# Stop the container
docker-compose down
Access the application at http://localhost:3000.
Access the Swagger UI documentation at:
http://localhost:3000/api-docs
The Swagger UI provides:
Base URL: http://localhost:3000/api
GET /health
Check if the API is running.
Response:
{
"success": true,
"message": "Todo API is running",
"timestamp": "2025-11-13T12:00:00.000Z"
}
GET /todos
Response:
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": false,
"createdAt": "2025-11-13T12:00:00.000Z",
"updatedAt": "2025-11-13T12:00:00.000Z"
}
],
"message": "Retrieved 1 todos"
}
GET /todos/:id
Response:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": false,
"createdAt": "2025-11-13T12:00:00.000Z",
"updatedAt": "2025-11-13T12:00:00.000Z"
}
}
POST /todos
Request Body:
{
"title": "Buy groceries",
"description": "Milk, eggs, bread"
}
Validation Rules:
title (required): String, 1-200 charactersdescription (optional): String, max 1000 charactersResponse: (201 Created)
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": false,
"createdAt": "2025-11-13T12:00:00.000Z",
"updatedAt": "2025-11-13T12:00:00.000Z"
},
"message": "Todo created successfully"
}
PUT /todos/:id
Request Body:
{
"title": "Buy groceries and cook dinner",
"description": "Updated description",
"completed": true
}
Validation Rules:
title (optional): String, 1-200 charactersdescription (optional): String, max 1000 characterscompleted (optional): BooleanResponse:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Buy groceries and cook dinner",
"description": "Updated description",
"completed": true,
"createdAt": "2025-11-13T12:00:00.000Z",
"updatedAt": "2025-11-13T12:05:00.000Z"
},
"message": "Todo updated successfully"
}
DELETE /todos/:id
Response:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": true,
"createdAt": "2025-11-13T12:00:00.000Z",
"updatedAt": "2025-11-13T12:05:00.000Z"
},
"message": "Todo deleted successfully"
}
GET /todos/stats
Response:
{
"success": true,
"data": {
"total": 10,
"completed": 6,
"pending": 4
}
}
All error responses follow this format:
{
"success": false,
"error": "Error message description"
}
Common HTTP status codes:
400 - Bad Request (validation errors)404 - Not Found500 - Internal Server Errornpm run dev - Start development server with auto-reloadnpm run build - Compile TypeScript to JavaScriptnpm run build:clean - Clean build directory and rebuildnpm start - Run compiled applicationnpm test - Run test suite with coveragenpm run test:watch - Run tests in watch modenpm run lint - Check code for linting errorsnpm run lint:fix - Fix linting errors automaticallynpm run format - Format code with Prettiernpm run format:check - Check code formatting# Run all tests with coverage
npm test
# Run tests in watch mode
npm run test:watch
Test coverage report will be generated in the coverage/ directory.
This project uses ESLint and Prettier for code quality and formatting:
# Check for linting issues
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Environment (development/production) | development |
PORT |
Server port | 3000 |
API_PREFIX |
API route prefix | /api |
This project includes automated CI/CD pipelines using GitHub Actions:
View the workflows in .github/workflows/:
ci.yml - Main CI/CD pipelinecodeql.yml - Security analysisWe welcome contributions! Please see CONTRIBUTING.md for detailed guidelines.
Quick start:
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)Please read our Code of Conduct before contributing.
This project is licensed under the MIT License - see the LICENSE file for details.
GDSC-UNC
Built with TypeScript, Express, and best practices in mind.