A REST API for tracking personal habits and managing streaks, built with Node.js, TypeScript, Express, and PostgreSQL.
- User authentication with JWT
- Create, read, update, and delete habits
- Daily habit tracking
- 7-day history view
- Automatic streak calculation
- Tag-based filtering
- Pagination support
- Rate limiting (100 requests/hour)
- Runtime: Node.js with TypeScript
- Framework: Express
- Database: PostgreSQL
- ORM: Prisma
- Authentication: JWT + bcrypt
- Validation: express-validator
- Rate Limiting: express-rate-limit
- Node.js (v18 or higher)
- PostgreSQL
- pnpm (or npm/yarn)
- Clone the repository
git clone <repository-url>
cd habit-tracker-api- Install dependencies
pnpm install- Configure environment variables
Create a .env file in the root directory:
DATABASE_URL="postgresql://user:password@localhost:5432/habit_tracker?schema=public"
JWT_SECRET="your-secret-key-here"
PORT=3000- Run database migrations
pnpm prisma:migrate- Generate Prisma Client
pnpm prisma:generateDevelopment mode:
pnpm devProduction build:
pnpm build
pnpm startAll habit-related endpoints require JWT authentication. Include the token in the Authorization header:
Authorization: Bearer <your-jwt-token>
POST /register
Register a new user.
Request:
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123"
}Response:
{
"success": true,
"message": "User registered successfully",
"data": {
"user": {
"id": "uuid",
"name": "John Doe",
"email": "john@example.com"
},
"token": "jwt-token"
}
}POST /login
Authenticate user and get JWT.
Request:
{
"email": "john@example.com",
"password": "password123"
}Response:
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": "uuid",
"name": "John Doe",
"email": "john@example.com"
},
"token": "jwt-token"
}
}POST /habits
Create a new habit.
Request:
{
"title": "Morning Exercise",
"description": "30 minutes of cardio",
"frequency": "daily",
"tags": ["health", "fitness"],
"reminderTime": "07:00"
}Response:
{
"success": true,
"message": "Habit created successfully",
"data": {
"id": "uuid",
"title": "Morning Exercise",
"description": "30 minutes of cardio",
"frequency": "daily",
"tags": ["health", "fitness"],
"reminderTime": "07:00",
"userId": "uuid",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
}GET /habits
Get all habits for the authenticated user.
Query Parameters:
tag(optional): Filter by tagpage(optional, default: 1): Page numberlimit(optional, default: 10): Items per page
Response:
{
"success": true,
"message": "Success",
"data": {
"habits": [...],
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3
}
}
}GET /habits/:id
Get a specific habit.
Response:
{
"success": true,
"message": "Success",
"data": {
"id": "uuid",
"title": "Morning Exercise",
...
}
}PUT /habits/:id
Update a habit.
Request (all fields optional):
{
"title": "Updated Title",
"description": "Updated description",
"frequency": "weekly",
"tags": ["new-tag"],
"reminderTime": "08:00"
}Response:
{
"success": true,
"message": "Habit updated successfully",
"data": { ... }
}DELETE /habits/:id
Delete a habit.
Response:
{
"success": true,
"message": "Habit deleted successfully",
"data": null
}POST /habits/:id/track
Mark habit as completed for today.
Response:
{
"success": true,
"message": "Habit tracked successfully",
"data": {
"id": "uuid",
"habitId": "uuid",
"date": "2025-01-01",
"completedAt": "2025-01-01T10:30:00.000Z"
}
}GET /habits/:id/history
Get last 7 days of tracking history and current streak.
Response:
{
"success": true,
"message": "Success",
"data": {
"history": [
{
"date": "2025-01-01",
"completed": true
},
{
"date": "2025-01-02",
"completed": false
},
...
],
"streak": 5
}
}All errors follow this format:
{
"success": false,
"message": "Error message",
"errors": [...]
}Common status codes:
- 400: Bad Request (validation errors)
- 401: Unauthorized (invalid/missing token)
- 404: Not Found
- 429: Too Many Requests (rate limit exceeded)
- 500: Internal Server Error
- id (UUID)
- name
- email (unique)
- password (hashed)
- createdAt
- updatedAt
- id (UUID)
- title
- description
- frequency (daily/weekly)
- tags (array)
- reminderTime
- userId (foreign key)
- createdAt
- updatedAt
- id (UUID)
- habitId (foreign key)
- date (unique per habit)
- completedAt
- Unique constraint: (habitId, date)
View and edit your database:
pnpm prisma:studioThe API is rate-limited to 100 requests per hour per IP address.
ISC