0% found this document useful (0 votes)
4 views7 pages

Express JS Learning Guide Final Edition

This document is a learning guide for Express.js, covering project setup, server responses, routing, middleware, CORS, SQLite integration, authentication, and shopping cart endpoints. It provides a step-by-step approach to building a small authenticated API with a shopping cart using SQLite for data persistence. The guide emphasizes best practices, error handling, and security considerations throughout the development process.

Uploaded by

musicpeyman
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views7 pages

Express JS Learning Guide Final Edition

This document is a learning guide for Express.js, covering project setup, server responses, routing, middleware, CORS, SQLite integration, authentication, and shopping cart endpoints. It provides a step-by-step approach to building a small authenticated API with a shopping cart using SQLite for data persistence. The guide emphasizes best practices, error handling, and security considerations throughout the development process.

Uploaded by

musicpeyman
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

📘 Express.

js Learning Guide
📑 Contents
1. ⚙️Project Setup

2. Basic Server & Responses

3. 🧩 Routing: Params & Query

4. 🧱 Middleware & Static Files

5. 🌐 CORS

6. 💾 SQLite: Setup & Queries

7. 🔐 Auth: Register / Login / Session

8. 🛒 Cart Endpoints

9. Protecting Routes

10. 🌍 HTTP Status Codes

11. 🧠 Best Practices

🎯 Goal & Scope


This mini-book teaches [Link] from setup to a small authenticated API with a shopping
cart, using SQLite for persistence. No exercises—pure explanation and code you can paste
and run.

⚙️Project Setup
Initialize a Node project and install Express. Use ES Modules for modern import/export.
npm init -y
npm install express
// In [Link] add:

"type": "module"

🟢 Tip — Keep secrets out of source code. Use environment variables.

🟢 Tip — Dependencies are tracked in "dependencies" inside [Link]. Avoid editing


node_modules or [Link].

Create a Basic Server


An Express app is a function we configure with middleware and routes, and then bind to a
port.

import express from 'express';


const app = express();
const PORT = 3000;
[Link](PORT, () => [Link](`Listening on ${PORT}`));

🟠 Note — Use [Link] in production platforms.

📤 Sending Responses
Use [Link] for JSON APIs and [Link] for text/HTML. Always terminate a request with a
response or next().

[Link]('/', (req, res) => {


[Link]({ ok: true });
});

📥 Understanding the Request Object


[Link] holds parsed request payloads (after [Link]()), [Link] holds path
params, and [Link] holds URL query strings.

[Link]([Link]());
[Link]('/search', (req, res) => {
const { q, page = 1 } = [Link];
[Link]({ q, page });
});

🧩 Routing: Params, Query, and Routers


Routers encapsulate related endpoints, improving organization and testability.

// routes/[Link]
import express from 'express';
import { productsController } from '../controllers/[Link]';
const router = [Link]();
[Link]('/products', productsController);
export default router;

// [Link]

import apiRouter from './routes/[Link]';


[Link]('/api', apiRouter);

// 404 fallback

[Link]((req, res) => [Link](404).json({ message: 'Not Found' }));

🧱 Middleware
Middleware runs in sequence. It can read/modify req and res, then call next() to continue.
Common uses: logging, parsing, security, auth.

[Link]((req, res, next) => {


[Link](`${[Link]} ${[Link]}`);
next();
});

// Built-in helpers

[Link]([Link]());
[Link]([Link]('public'));

🌐 CORS
Enable cross-origin requests when your frontend is hosted on another origin.

import cors from 'cors';


[Link](cors({
origin: '[Link]
methods: ['GET','POST','PUT','DELETE'],
}));

💾 SQLite Setup
SQLite is a serverless SQL database stored in a single file. We use the sqlite and sqlite3
packages together with async/await.

npm install sqlite3 sqlite

import sqlite3 from 'sqlite3';


import { open } from 'sqlite';
import path from 'node:path';

export async function getDBConnection() {


return open({ filename: [Link]('[Link]'), driver: [Link] });
}

export async function migrate() {


const db = await getDBConnection();
await [Link](`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
email TEXT UNIQUE,
password TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT, artist TEXT, genre TEXT, price REAL
);
CREATE TABLE IF NOT EXISTS cart_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
product_id INTEGER,
quantity INTEGER DEFAULT 1,
FOREIGN KEY(user_id) REFERENCES users(id),
FOREIGN KEY(product_id) REFERENCES products(id)
);
`);
await [Link]();
}

🔎 Dynamic Queries: Filtering & Search


Compose SQL based on user-supplied query params. Always bind values to placeholders (?)
to avoid SQL injection.

export async function listProducts(req, res) {


const db = await getDBConnection();
let query = 'SELECT * FROM products';
const params = [];
const { genre, search } = [Link];
if (genre) {
query += ' WHERE genre = ?';
[Link](genre);
} else if (search) {
query += ' WHERE title LIKE ? OR artist LIKE ? OR genre LIKE ?';
const s = `%${search}%`;
[Link](s, s, s);
}
const rows = await [Link](query, params);
[Link](rows);
}

🟢 Tip — Use parameterized queries (?) to prevent SQL injection.

🔐 Authentication with Sessions


We use express-session to persist a user ID across requests after login. Passwords are
hashed with bcryptjs.

npm install express-session validator bcryptjs

import session from 'express-session';


[Link](session({
secret: 'secret',
resave: false,
saveUninitialized: false
}));

import validator from 'validator';


import bcrypt from 'bcryptjs';
import { getDBConnection } from './[Link]';

export async function registerUser(req, res) {


const { username, email, password } = [Link];
if (!username || !email || !password) return [Link](400).json({ error: 'All fields required' });
if (![Link](email)) return [Link](400).json({ error: 'Invalid email' });
const hash = await [Link](password, 10);
const db = await getDBConnection();
await [Link]('INSERT INTO users (username,email,password) VALUES (?,?,?)', [[Link](),
[Link](), hash]);
[Link](201).json({ message: 'User registered' });
}

export async function loginUser(req, res) {


const { username, password } = [Link];
const db = await getDBConnection();
const user = await [Link]('SELECT * FROM users WHERE username = ?', [[Link]()]);
if (!user) return [Link](401).json({ error: 'Invalid credentials' });
const ok = await [Link](password, [Link]);
if (!ok) return [Link](401).json({ error: 'Invalid credentials' });
[Link] = [Link];
[Link]({ message: 'Logged in' });
}

export function logout(req, res) {


[Link](() => [Link]({ message: 'Logged out' }));
}

Protecting Routes
function requireAuth(req, res, next) {
if (![Link]) return [Link](403).json({ error: 'Unauthorized' });
next();
}
[Link]('/api/cart', requireAuth);

🛒 Shopping Cart Endpoints


The cart is per-user and stores product references and quantities.

export async function getAll(req, res) {


const db = await getDBConnection();
const items = await [Link](`
SELECT [Link] AS cartItemId, [Link], [Link], [Link], [Link]
FROM cart_items ci
JOIN products p ON [Link] = ci.product_id
WHERE ci.user_id = ?
`, [[Link]]);
[Link]({ items });
}

export async function addToCart(req, res) {


const db = await getDBConnection();
const productId = parseInt([Link], 10);
if (isNaN(productId)) return [Link](400).json({ error: 'Invalid product ID' });
const userId = [Link];
const existing = await [Link]('SELECT * FROM cart_items WHERE user_id = ? AND product_id = ?',
[userId, productId]);
if (existing) {
await [Link]('UPDATE cart_items SET quantity = quantity + 1 WHERE id = ?', [[Link]]);
} else {
await [Link]('INSERT INTO cart_items (user_id, product_id, quantity) VALUES (?, ?, 1)', [userId,
productId]);
}
[Link]({ message: 'Added to cart' });
}

export async function deleteAll(req, res) {


const db = await getDBConnection();
await [Link]('DELETE FROM cart_items WHERE user_id = ?', [[Link]]);
[Link](204).send();
}
export async function deleteItem(req, res) {
const db = await getDBConnection();
const itemId = parseInt([Link], 10);
if (isNaN(itemId)) return [Link](400).json({ error: 'Invalid item ID' });
const item = await [Link]('SELECT quantity FROM cart_items WHERE id = ? AND user_id = ?',
[itemId, [Link]]);
if (!item) return [Link](400).json({ error: 'Item not found' });
await [Link]('DELETE FROM cart_items WHERE id = ? AND user_id = ?', [itemId,
[Link]]);
[Link](204).send();
}

export async function getCartCount(req, res) {


const db = await getDBConnection();
const result = await [Link]('SELECT SUM(quantity) AS totalItems FROM cart_items WHERE user_id
= ?', [[Link]]);
[Link]({ totalItems: [Link] || 0 });
}

🧰 Error Handling & Status Codes


Use centralized error handlers. Always send appropriate HTTP status codes.

// [Link]((req, res) => [Link](404).json({ message: 'Not Found' }));

// Error [Link]((err, req, res, next) => {


[Link](err);
[Link](500).json({ error: 'Internal Server Error' });
});

Status overview: 2xx Success • 4xx Client Error • 5xx Server Error. Prefer 201 for resource
creation and 204 for no-content deletes.

✅ Wrap-up
You now have a minimal but complete pattern: Express app → routers → middleware →
SQLite → session auth → protected cart endpoints. Expand by adding validation layers and
structured logging.

You might also like