Skip to content

dev48v/nodejs-from-zero

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Node.js + Express from Zero: Product CRUD REST API

Day 2 of the from-zero series. Build a complete REST API from scratch — one step at a time.


What You'll Build

A Product CRUD REST API with:

  • Node.js as the runtime (like JVM for Java)
  • Express as the web framework (like Spring Boot for Java)
  • MySQL as the database
  • mysql2 as the database driver (with async/await support)
  • Layered architecture: Routes → Controller → Service → Model → Database

By the end, you'll have 5 working endpoints that can Create, Read, Update, and Delete products.


Prerequisites

Tool Version Check Command Install From
Node.js 18+ node --version https://nodejs.org/
npm 9+ npm --version (comes with Node.js)
MySQL 5.7+ mysql --version https://dev.mysql.com/ or XAMPP

Make sure MySQL is running before you start (e.g., start XAMPP → MySQL).


How to Follow This Tutorial

This project was built in 8 steps, each as a separate git commit.

# See all steps in order (oldest first)
git log --oneline --reverse

# See exactly what changed in each step
git show <commit-hash>

# Or see a specific step's diff
git log --oneline --reverse   # find the hash
git show abc1234              # view that step's changes

How to Run

# 1. Clone the repo
git clone https://github.com/dev48v/nodejs-from-zero.git
cd nodejs-from-zero

# 2. Install dependencies
npm install

# 3. Create your .env file (copy the example)
cp .env.example .env
# Edit .env if your MySQL user/password is different from root/(empty)

# 4. Start the server (it auto-creates the database and table)
npm start

# You should see:
# > Database initialized successfully
# > Server is running on http://localhost:3000

Test the API

Health check

curl http://localhost:3000/

Load seed data (optional — gives you 5 sample products)

mysql -u root nodejs_from_zero_db < seed.sql

Get all products

curl http://localhost:3000/api/products

Get a product by ID

curl http://localhost:3000/api/products/1

Create a product

curl -X POST http://localhost:3000/api/products \
  -H "Content-Type: application/json" \
  -d '{"name": "Wireless Earbuds", "description": "Bluetooth 5.3, 30hr battery", "price": 59.99, "quantity": 50}'

Update a product

curl -X PUT http://localhost:3000/api/products/1 \
  -H "Content-Type: application/json" \
  -d '{"name": "MacBook Pro 16\" (Updated)", "description": "M3 Max chip, 36GB RAM", "price": 3499.99, "quantity": 10}'

Delete a product

curl -X DELETE http://localhost:3000/api/products/1
# Returns 204 No Content (empty response = success)

Project Structure

nodejs-from-zero/
├── .env.example                 ← Environment variable template
├── .gitignore                   ← Ignores node_modules, .env, logs
├── package.json                 ← Dependencies and scripts
├── seed.sql                     ← Sample data (5 products)          [STEP 8]
├── GUIDE.md                     ← This file
├── README.md                    ← Same as GUIDE.md
└── src/
    ├── app.js                   ← Entry point: Express setup        [STEP 1]
    ├── config/
    │   └── database.js          ← MySQL pool + auto-init            [STEP 2]
    ├── models/
    │   └── Product.js           ← Raw SQL CRUD queries              [STEP 3]
    ├── dto/
    │   └── ProductDTO.js        ← DB row ↔ API response mapping     [STEP 4]
    ├── services/
    │   └── ProductService.js    ← Business logic + validation       [STEP 5]
    ├── controllers/
    │   └── ProductController.js ← HTTP handlers (req/res)           [STEP 6]
    ├── routes/
    │   └── productRoutes.js     ← URL → Controller wiring           [STEP 7]
    └── middleware/
        └── errorHandler.js      ← Global error middleware           [STEP 8]

Architecture (Request Flow)

Client (curl / Postman / browser)
  │
  ▼
┌─────────────────────────────────────────────────┐
│  app.js                                          │
│  ├── express.json() middleware (parse body)       │
│  ├── GET / (health check)                        │
│  ├── /api/products → productRoutes.js            │
│  └── errorHandler middleware (catch all errors)   │
└─────────────────────────────────────────────────┘
  │
  ▼
┌─────────────────────────────────────────────────┐
│  productRoutes.js                                │
│  Maps HTTP method + path → controller function   │
│  GET /        → getAll                           │
│  GET /:id     → getById                          │
│  POST /       → create                           │
│  PUT /:id     → update                           │
│  DELETE /:id  → remove                           │
└─────────────────────────────────────────────────┘
  │
  ▼
┌─────────────────────────────────────────────────┐
│  ProductController.js                            │
│  Reads req (params, body) → calls service        │
│  Sends res (status code, JSON body)              │
│  Passes errors to next() → errorHandler          │
└─────────────────────────────────────────────────┘
  │
  ▼
┌─────────────────────────────────────────────────┐
│  ProductService.js                               │
│  Validates input → calls model → maps with DTO   │
│  Throws errors with statusCode (400, 404)        │
└─────────────────────────────────────────────────┘
  │
  ▼
┌──────────────────┐    ┌─────────────────────────┐
│  ProductDTO.js   │    │  Product.js (Model)      │
│  toDto()         │    │  findAll(), findById(),  │
│  toEntity()      │    │  create(), update(),     │
│  toDtoList()     │    │  remove()                │
└──────────────────┘    └─────────────────────────┘
                              │
                              ▼
                        ┌───────────┐
                        │  MySQL DB │
                        │  (pool)   │
                        └───────────┘

Dependencies Explained

Package Why
express Web framework — handles routing, middleware, HTTP requests/responses
mysql2 MySQL driver with promise/async-await support (faster than mysql pkg)
dotenv Loads .env file into process.env — keeps secrets out of code

Key Differences from Spring Boot (Day 1)

Concept Spring Boot (Java) Express (Node.js)
Entry point @SpringBootApplication class app.js with app.listen()
Dependency injection @Autowired / constructor inject require() / import
ORM JPA/Hibernate (auto-maps) Raw SQL with mysql2 (manual)
Annotations @GetMapping, @Entity, etc. router.get(), plain objects
Error handling @ControllerAdvice app.use((err, req, res, next)) middleware
Config application.properties .env + dotenv
Build tool Maven / Gradle npm
Hot reload Spring DevTools node --watch (built-in)

Next Steps

Once you're comfortable with this project, try:

  1. Add paginationGET /api/products?page=1&limit=10
  2. Add search/filterGET /api/products?name=laptop&minPrice=100
  3. Use an ORM — Replace raw SQL with Sequelize or Prisma
  4. Add validation — Use a library like joi or express-validator
  5. Add tests — Use Jest + Supertest for API testing
  6. Dockerize — Create a Dockerfile so anyone can run this with docker compose up

About

Day 2: Node.js + Express Product CRUD REST API - from-zero learning series

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors