Skip to content

Revoltzin/ToDoList-API

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ToDoList API REST API for managing users and to-do lists, with JWT‑based authentication, PostgreSQL persistence (via Docker), and password hashing using bcrypt.

This project is designed as a solid backend foundation, following good practices in project structure, authentication, authorization, and error handling.

Technologies Node.js (Express 5)

PostgreSQL (Docker + Docker Compose)

JWT (JSON Web Token) for authentication

bcrypt for password hashing

dotenv for environment variables

Prerequisites Before running the project, make sure you have:

Node.js (v18+ recommended)

npm or yarn

Docker and Docker Compose

Git (optional, if cloning the repository)

Getting started

  1. Clone the repository

git clone https://github.com/Revoltzin/ToDoList-API cd YOUR_REPOSITORY

  1. Configure PostgreSQL with Docker Create a docker-compose.yml file in the project root (if you don’t already have one):

version: '3.8'

services: postgres: image: postgres:16 container_name: postgres_app environment: POSTGRES_DB: usersdb POSTGRES_USER: postgres POSTGRES_PASSWORD: 123456 ports: - "5433:5432" volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped

volumes: postgres_data:

Start the PostgreSQL container:

docker-compose up -d postgres

  1. Configure environment variables

Create a .env file in the project root:

DB_HOST=localhost DB_PORT=5433 DB_NAME=usersdb DB_USER=postgres DB_PASSWORD=123456

JWT_SECRET=your_very_secure_secret_key_here

Adjust values as needed for your environment.

  1. Install dependencies

npm install

or

yarn install

  1. Create the database tables Connect to the database inside the PostgreSQL container:

docker exec -it postgres_app psql -U postgres -d usersdb Then run:

CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

CREATE TABLE IF NOT EXISTS todolists ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, description TEXT, is_done BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

\q

  1. Start the server

npm start

or, if you use nodemon

npm run dev

The API should now be running at: http://localhost:3000

Project structure

src/ app/ Controller/ UsersController.js ListsController.js Repository/ UsersRepository.js ToDoListsRepository.js middlewares/ auth.js database/ index.js routes/ users.routes.js todolists.routes.js utils/ asyncHandler.js app.js docker-compose.yml .env package.json

This structure separates concerns:

Controller: HTTP layer (request/response handling).

Repository: Data access (PostgreSQL queries).

middlewares: Authentication and other cross‑cutting middleware.

utils: Helpers such as async error handling.

database: Database connection pool configuration.

API endpoints Authentication & Users Register user Method: POST

URL: /users

Request body (JSON):

json { "name": "Your Name", "email": "you@example.com", "password": "your_password" } Response (201 Created): Returns the created user (password is stored hashed in the database).

Login Method: POST

URL: /users/login

Request body (JSON):

json { "email": "you@example.com", "password": "your_password" } Response (200 OK):

json { "token": "JWT_TOKEN_HERE" } You will use this token in the Authorization header for protected routes.

List users (optional, if implemented) Method: GET

URL: /users

Depending on your implementation, this endpoint may be protected by JWT.

ToDo Lists (protected routes) All to‑do list routes require authentication.

Required header:

Key: Authorization

Value: Bearer YOUR_JWT_TOKEN

The userId is extracted from the token and used to ensure that each user only accesses their own lists.

Get all lists for the authenticated user Method: GET

URL: /todolists

Response (200 OK) example:

json [ { "id": 1, "title": "My first task", "description": "just a test", "is_done": false, "created_at": "2025-12-10T20:00:00.000Z" } ] Create a new to‑do list Method: POST

URL: /todolists

Request body (JSON):

json { "title": "Study Node.js", "description": "Review JWT authentication" } Response (201 Created):

json { "id": 1, "user_id": 1, "title": "Study Node.js", "description": "Review JWT authentication", "is_done": false, "created_at": "2025-12-10T20:00:00.000Z" } Update a to‑do list Method: PUT

URL: /todolists/:id

Example: PUT /todolists/1

Request body (JSON):

json { "title": "Study Node.js (updated)", "description": "Review JWT and middleware", "is_done": true } Response (200 OK): Returns the updated to‑do list, or 404 Not Found if the list does not belong to the authenticated user or does not exist.

Delete a to‑do list Method: DELETE

URL: /todolists/:id

Example: DELETE /todolists/1

Response (204 No Content): Empty body if deletion succeeds, or 404 Not Found if the list does not belong to the authenticated user or does not exist.

Authentication & authorization Login returns a JWT whose payload includes at least userId (and optionally email).

The authentication middleware:

Reads the Authorization header in the Bearer TOKEN format.

Verifies the token using jwt.verify and JWT_SECRET.

On success, attaches the decoded payload to req.user.

If there is no token → responds 401 Token required.

If token is invalid or expired → responds 403 Invalid or expired token.

To‑do list endpoints always rely on req.user.userId so users can only access their own data.

Error handling Controllers are implemented as async functions.

Routes wrap controllers using an asyncHandler helper to forward async errors to the global error handler.

Global error middleware (example):

js app.use((err, req, res, next) => { console.error(err); return res.status(500).json({ error: 'Internal server error' }); }); You can extend this to handle validation errors, database errors, etc., with more specific status codes and messages.

Testing with Insomnia/Postman Suggested flow:

Register a user

POST /users with JSON body { name, email, password }.

Login

POST /users/login and copy the token from the response.

Use protected routes

Add header Authorization: Bearer YOUR_TOKEN to all /todolists requests.

Test:

POST /todolists to create a task.

GET /todolists to list tasks.

PUT /todolists/:id to update a task.

DELETE /todolists/:id to remove a task.

thats it, thanks and enjoy the project.

About

ToDoList Api using JS, NodeJs and postgres - TRAINING

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors