REST API for a notes application built with Express.js, MongoDB, and Redis.
The project focuses on authentication, API design, validation, testing, and common backend security practices.
- π JWT Authentication β Access and refresh tokens via HTTP-only cookies
- π‘οΈ CSRF Protection β XSRF-TOKEN validation for state-changing requests
- π Full CRUD β Create, read, update, and delete notes
- π Search & Filter β Full-text search + tag-based filtering
- π Pagination β Efficient pagination for large collections
- π OpenAPI/Swagger β Interactive API documentation
- π Production Practices β Rate limiting, logging, error handling, security headers
- π§ͺ Testing β Comprehensive test suite with Jest + Supertest
| Category | Technology |
|---|---|
| Runtime | Node.js |
| Framework | Express.js |
| Database | MongoDB (Mongoose) |
| Cache | Redis |
| Containerization | Docker, Docker Compose |
| Auth | JWT, bcrypt |
| Validation | express-validator |
| Docs | Swagger UI, OpenAPI 3.0 |
| Logging | Winston + Morgan |
| Testing | Jest + Supertest |
| Linting | ESLint + Prettier |
- Docker & Docker Compose (recommended)
- Node.js >= 18 (for local development)
# Clone repository
git clone https://github.com/n1kFord/notes-rest-api.git
cd notes-rest-api
# Start all services (MongoDB, Redis, and API)
docker compose up -d
# Check logs
docker compose logs -f
# Access API
curl http://localhost:8080/health
# Open Swagger documentation
http://localhost:8080/api/docs
# Stop services
docker compose down
# Stop and remove volumes (clears database)
docker compose down -v# Install dependencies
npm install
# Setup environment
cp .env.example .env
# Edit .env with your configuration
# Start MongoDB and Redis (using Docker)
docker compose up -d mongo redis
# Start development server
npm run dev # or npm start
# Production mode
npm start# Server
PORT=8080
NODE_ENV=development
# MongoDB
MONGODB_URI=mongodb://localhost:27017/notes_app
# Redis
REDIS_URL=redis://localhost:6379
# JWT Secrets (generate strong secrets β at least 32 chars!)
JWT_SECRET=your_super_secret_jwt_key_min_32_chars
JWT_REFRESH_SECRET=your_super_secret_refresh_key_min_32_chars
# Token Expiry (optional)
ACCESS_TOKEN_EXPIRY=15m
REFRESH_TOKEN_EXPIRY=7dInteractive Swagger UI is available at /api/docs when the server is running.
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /register |
Register new user | β |
| POST | /login |
Login user | β |
| POST | /refresh |
Refresh access token | β |
| POST | /logout |
Logout user | β |
| GET | /me |
Get current user info | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET | / |
Get all user notes | β |
| GET | /:id |
Get specific note | β |
| POST | / |
Create new note | β |
| PUT | /:id |
Update note | β |
| DELETE | /:id |
Delete note | β |
| GET | /search?q=query |
Search notes | β |
| GET | /tags/:tag |
Get notes by tag | β |
POST /api/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "Password123",
"confirmPassword": "Password123"
}Response: 201 Created
{ "success": true }POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "Password123"
}Response: 200 OK
{ "success": true }Cookies set:
| Cookie | Description |
|---|---|
token |
JWT access token (HttpOnly) |
refreshToken |
JWT refresh token (HttpOnly) |
XSRF-TOKEN |
CSRF protection token |
POST /api/notes
Cookie: token=<access_token>; XSRF-TOKEN=<csrf_token>
x-xsrf-token: <csrf_token>
{
"title": "My First Note",
"content": "This is the content of my first note",
"tags": ["work", "important"]
}Response: 201 Created
{
"_id": "507f1f77bcf86cd799439011",
"title": "My First Note",
"content": "This is the content of my first note",
"userId": "507f1f77bcf86cd799439001",
"tags": ["work", "important"],
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:00.000Z"
}GET /api/notes?page=1&limit=10
Cookie: token=<access_token>Response: 200 OK
{
"notes": [...],
"total": 25,
"page": 1,
"totalPages": 3
}GET /api/notes/search?q=project&page=1&limit=10
Cookie: token=<access_token>{
_id: ObjectId,
email: String (unique, indexed),
password: String (bcrypt hashed),
createdAt: Date,
updatedAt: Date
}{
_id: ObjectId,
title: String (required, max 200),
content: String (required),
userId: ObjectId (ref: User, indexed),
tags: [String] (indexed),
createdAt: Date,
updatedAt: Date
}Indexes:
{ userId: 1, createdAt: -1 }β efficient pagination{ userId: 1, tags: 1 }β tag filtering{ title: "text", content: "text" }β full-text search
- JWT authentication using HTTP-only cookies
- Refresh token rotation
- CSRF protection
- Request validation
- Rate limiting
- Password hashing with bcrypt
- Centralized error handling
- Request logging
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# CI mode
npm run test:cisrc/
βββ config/ # Database, Redis, and app configuration
βββ middlewares/ # Authentication, CSRF, validation, error handling
βββ models/ # MongoDB schemas
βββ routers/ # API route handlers
βββ store/ # Redis data storage
βββ utils/ # Shared helpers and utilities
βββ validations/ # Request validation rules
βββ tests/ # API and integration tests
βββ index.js # Application entry point
βββ swagger.js # OpenAPI configuration
docker-compose.yml # Docker services configuration
Dockerfile # API container image
| Code | Description |
|---|---|
| 200 | OK |
| 201 | Created |
| 204 | No Content |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden (CSRF) |
| 404 | Not Found |
| 409 | Conflict |
| 429 | Too Many Requests |
| 500 | Internal Server Error |
| Command | Description |
|---|---|
npm start |
Production start |
npm run dev |
Development with nodemon |
npm test |
Run tests |
npm run test:ci |
CI tests with coverage |
npm run lint |
ESLint check |
npm run lint:fix |
ESLint auto-fix |
npm run format |
Prettier format |
npm run format:check |
Prettier check |
npm run validate |
Lint + format + test |
This project is licensed under the MIT License.
Feel free to use, modify, and distribute with attribution.
π‘ Created with care by @n1kFord
Built with β€οΈ for learning modern Node.js backend development