Back

พื้นฐานการพัฒนา RESTful API ด้วย Node.js, Express และ MySQLBlur image

1. วัตถุประสงค์#

บทความนี้จะแนะนำขั้นตอนการออกแบบและพัฒนา RESTful API สำหรับจัดการทรัพยากร ผู้ใช้งาน (Users), สินค้า (Products), คำสั่งซื้อ (Orders) และทรัพยากรแบบซ้อน (Nested Resources) เพื่อแสดงข้อมูลคำสั่งซื้อทั้งหมดของผู้ใช้งาน และสินค้าทั้งหมดที่อยู่ในคำสั่งซื้อ โดยใช้ Node.js และ Express เชื่อมต่อกับฐานข้อมูล MySQL โดยตรงด้วย mysql2 พร้อมทดสอบด้วย Postman


2. ติดตั้งโปรแกรมและตั้งค่าฐานข้อมูล#

  1. ติดตั้ง Node.js version LTS ดาวน์โหลด Node.js เวอร์ชัน LTS (Long Term Support) จาก https://nodejs.org เลือกเวอร์ชัน LTS ที่แนะนำสำหรับการใช้งานในการพัฒนา

    การตั้งค่า:

    • ดาวน์โหลดไฟล์ installer ที่เหมาะสมกับระบบปฏิบัติการ (Windows, macOS, หรือ Linux)
    • ติดตั้งโดยการดับเบิลคลิกไฟล์ installer และปฏิบัติตามขั้นตอนการติดตั้ง
    • หลังจากติดตั้งเสร็จสิ้น ให้เปิด Command Prompt หรือ Terminal และตรวจสอบการติดตั้งด้วยคำสั่ง:
      node --version
      npm --version
      bash
    • ถ้าติดตั้งสำเร็จ จะแสดงเวอร์ชันของ Node.js และ npm
  2. ติดตั้ง XAMPP (MySQL + phpMyAdmin) ดาวน์โหลดและติดตั้ง XAMPP จาก https://www.apachefriends.org เลือกเวอร์ชันที่เหมาะสมกับระบบปฏิบัติการ

    การตั้งค่า:

    • เมื่อติดตั้งเสร็จสิ้น ให้เปิด XAMPP Control Panel และตั้งค่า Apache และ MySQL ให้เป็น Service ดังภาพ (ต้องใช้สิทธิ Administrator) ตั้งค่า Apache และ MySQL ให้เป็น Service
    • Start บริการ Apache และ MySQL เพื่อให้สามารถใช้งานเว็บเซิร์ฟเวอร์และฐานข้อมูลได้
    • เปิดเว็บเบราว์เซอร์ไปที่ http://localhost/phpmyadmin
    • คลิกที่แท็บ Databases
    • ในส่วน Create database ให้ตั้งชื่อฐานข้อมูลว่า express_mysql_db แล้วคลิก Create
  3. ติดตั้ง Postman ดาวน์โหลด Postman ได้ที่ https://www.postman.com/downloads/ ติดตั้งและเปิดใช้งาน Postman จะใช้ Postman ในการทดสอบ API endpoints (GET, POST, PUT, DELETE)


3. ตั้งค่าโปรเจคและติดตั้ง MySQL Driver#

  1. สร้างโปรเจค Node.js เปิด Terminal หรือ Command Prompt แล้วรันคำสั่งเหล่านี้:

    mkdir api-mysql
    cd api-mysql
    npm init -y
    npm install express cors body-parser mysql2
    code . # เปิด VS Code ในโฟลเดอร์โปรเจกต์ (ถ้าติดตั้ง)
    bash
  2. สร้างไฟล์ .env สร้างไฟล์ .env ใน root project เพื่อเก็บค่าการเชื่อมต่อฐานข้อมูล:

    DB_HOST=localhost
    DB_USER=root
    DB_PASSWORD=
    DB_NAME=express_mysql_db
    DB_PORT=3306
    plaintext
    • DB_HOST: Host ของ MySQL (localhost)
    • DB_USER: ชื่อผู้ใช้ฐานข้อมูล (root สำหรับ XAMPP)
    • DB_PASSWORD: รหัสผ่าน (เว้นว่างไว้สำหรับ XAMPP ถ้าไม่ได้ตั้งค่า)
    • DB_NAME: ชื่อฐานข้อมูล
    • DB_PORT: Port ของ MySQL (3306)

4. สร้างตารางในฐานข้อมูล#

เปิด phpMyAdmin ที่ http://localhost/phpmyadmin และไปที่ฐานข้อมูล express_mysql_db จากนั้นคลิกที่แท็บ SQL และวางคำสั่ง SQL ต่อไปนี้เพื่อสร้างตาราง:

-- สร้างตาราง Users
CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  fname VARCHAR(100) NOT NULL,
  lname VARCHAR(100) NOT NULL,
  username VARCHAR(50) NOT NULL UNIQUE,
  email VARCHAR(100) NOT NULL UNIQUE,
  avatar VARCHAR(255) NULL
);

-- สร้างตาราง Products
CREATE TABLE products (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(200) NOT NULL,
  price INT NOT NULL
);

-- สร้างตาราง Orders
CREATE TABLE orders (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- สร้างตาราง Order_Product (ตารางเชื่อมระหว่าง Orders และ Products)
CREATE TABLE order_product (
  id INT AUTO_INCREMENT PRIMARY KEY,
  order_id INT NOT NULL,
  product_id INT NOT NULL,
  FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
  FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);
sql

สรุปโครงสร้างตาราง#

ตารางความสัมพันธ์ประเภท
usersมีหลายคำสั่งซื้อ (has many orders)One-to-Many
ordersถูกสร้างโดยผู้ใช้คนเดียว (belongs to one user)Many-to-One
ordersมีหลายสินค้า (has many products)Many-to-Many
productsอยู่ในหลายคำสั่งซื้อ (appears in many orders)Many-to-Many
order_productเชื่อมตาราง orders และ productsJoin table

ดูผลลัพธ์ได้ที่ฐานข้อมูล express_mysql_db ผลลัพธ์จากการสร้างตาราง

คำอธิบาย SQL ที่ใช้ในการสร้างตาราง#

CREATE TABLE - คำสั่งสร้างตารางใหม่:

CREATE TABLE table_name (
  column_name data_type constraints
);
sql

Data Types ที่ใช้บ่อย:

  • INT - ข้อมูลตัวเลขจำนวนเต็ม
  • VARCHAR(n) - ข้อมูลตัวอักษรความยาวไม่เกิน n ตัวอักษร
  • TIMESTAMP - ข้อมูลวันที่และเวลา
  • TEXT - ข้อมูลตัวอักษรความยาวไม่จำกัด

Constraints ที่ใช้บ่อย:

  • PRIMARY KEY - คีย์หลัก ใช้ระบุแต่ละแถวให้ไม่ซ้ำกัน
  • AUTO_INCREMENT - เลขที่เพิ่มขึ้นอัตโนมัติ (1, 2, 3, …)
  • NOT NULL - ข้อมูลต้องไม่เป็นค่าว่าง
  • UNIQUE - ข้อมูลต้องไม่ซ้ำกัน
  • DEFAULT - ค่าเริ่มต้นเมื่อไม่ได้ระบุข้อมูล

ความสัมพันธ์ระหว่างตาราง (Foreign Key):

FOREIGN KEY (column_name) REFERENCES other_table(id)
ON DELETE CASCADE   -- ลบข้อมูลที่เกี่ยวข้องเมื่อข้อมูลหลักถูกลบ
sql

ตัวอย่าง:

-- ตาราง users เก็บข้อมูลผู้ใช้
id INT AUTO_INCREMENT PRIMARY KEY  -- รหัสผู้ใช้ (เพิ่มอัตโนมัติ)
username VARCHAR(50) NOT NULL UNIQUE  -- ชื่อผู้ใช้ (ไม่ซ้ำกัน)

-- ตาราง orders เก็บคำสั่งซื้อ
user_id INT NOT NULL
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
-- user_id เชื่อมโยงกับ id ในตาราง users
-- เมื่อลบ user ข้อมูลคำสั่งซื้อจะถูกลบไปด้วย
sql

5. เพิ่มข้อมูลตัวอย่าง (Seed Data)#

หลังจากสร้างตารางเสร็จแล้ว เราต้องการข้อมูลตัวอย่างเพื่อทดสอบ API ให้ทำงานได้ทันที ให้เปิด phpMyAdmin ไปที่ฐานข้อมูล express_mysql_db และคลิกที่แท็บ SQL จากนั้นวางคำสั่ง SQL ต่อไปนี้:

-- เพิ่มข้อมูล Users
INSERT INTO users (id, fname, lname, username, email, avatar) VALUES
(1, 'Karn', 'Yong', 'karn.yong', 'karn.yong@melivecode.com', 'https://www.melivecode.com/users/1.png'),
(2, 'Parkpoom', 'Chaisiriprasert', 'parkpoom', 'parkpoom@melivecode.com', 'https://www.melivecode.com/users/2.png');

-- เพิ่มข้อมูล Products
INSERT INTO products (id, name, price) VALUES
(1, 'Laptop', 39999),
(2, 'Smartphone', 19999),
(3, 'Monitor', 7999);

-- เพิ่มข้อมูล Orders
INSERT INTO orders (id, user_id) VALUES
(1, 1),
(2, 2),
(3, 1);

-- เพิ่มข้อมูล Order_Product (เชื่อมโยงคำสั่งซื้อกับสินค้า)
INSERT INTO order_product (order_id, product_id) VALUES
-- คำสั่งซื้อ #1 (Karn) มี Laptop และ Smartphone
(1, 1),
(1, 2),
-- คำสั่งซื้อ #2 (Parkpoom) มี Smartphone
(2, 2),
-- คำสั่งซื้อ #3 (Karn) มี Smartphone และ Monitor
(3, 2),
(3, 3);
sql

คำอธิบาย SQL ที่ใช้ในการเพิ่มข้อมูล#

INSERT INTO - คำสั่งเพิ่มข้อมูลใหม่:

INSERT INTO table_name (column1, column2) VALUES (value1, value2);
sql

เพิ่มข้อมูลหลายแถวพร้อมกัน:

INSERT INTO users (fname, lname, email) VALUES
('Karn', 'Yong', 'karn@example.com'),
('Parkpoom', 'Chaisiriprasert', 'parkpoom@example.com');
sql

ข้อมูลตัวอย่างที่เพิ่ม:

ตารางข้อมูลที่เพิ่ม
Users2 ผู้ใช้: Karn และ Parkpoom
Products3 สินค้า: Laptop, Smartphone, Monitor
Orders3 คำสั่งซื้อ
Order_Productเชื่อมโยงคำสั่งซื้อกับสินค้า

ความสัมพันธ์ของข้อมูลตัวอย่าง:

  • Karn (id: 1) สั่งซื้อ 2 ครั้ง:
    • คำสั่งซื้อ #1: Laptop + Smartphone = 59,998 บาท
    • คำสั่งซื้อ #3: Smartphone + Monitor = 27,998 บาท
  • Parkpoom (id: 2) สั่งซื้อ 1 ครั้ง:
    • คำสั่งซื้อ #2: Smartphone = 19,999 บาท

6. สร้างไฟล์เชื่อมต่อฐานข้อมูล#

สร้างไฟล์ src/db.js เพื่อสร้าง connection pool สำหรับเชื่อมต่อกับฐานข้อมูล MySQL:

// src/db.js
const mysql = require('mysql2/promise');

// สร้าง connection pool
const pool = mysql.createPool({
  host: process.env.DB_HOST || 'localhost',
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || '',
  database: process.env.DB_NAME || 'express_mysql_db',
  port: process.env.DB_PORT || 3306,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

module.exports = pool;
javascript

คำอธิบาย Connection Pool#

Connection Pool คือการเก็บการเชื่อมต่อฐานข้อมูลไว้ใช้ร่วมกัน เพื่อไม่ต้องเปิด-ปิดการเชื่อมต่อใหม่ทุกครั้ง


7. คำสั่ง SQL พื้นฐานที่ใช้ใน RESTful API#

SELECT - ดึงข้อมูล#

ดึงข้อมูลทั้งหมด:

SELECT * FROM users;
sql

ดึงข้อมูลตามเงื่อนไข:

SELECT * FROM users WHERE id = 1;
sql

ดึงข้อมูลบางคอลัมน์:

SELECT fname, lname, email FROM users;
sql

INSERT - เพิ่มข้อมูล#

เพิ่มข้อมูลใหม่:

INSERT INTO users (fname, lname, username, email) VALUES ('Anna', 'Dee', 'anna.dee', 'Anna@example.com');
sql

ใน JavaScript (ใช้ parameter):

const sql = 'INSERT INTO users (fname, lname, username, email) VALUES (?, ?, ?, ?)';
await pool.query(sql, ['Anna', 'Dee', 'anna.dee', 'Anna@example.com']);
javascript

UPDATE - อัปเดตข้อมูล#

อัปเดตข้อมูล:

UPDATE users SET fname = 'Jane', email = 'jane@example.com' WHERE id = 3;
sql

ใน JavaScript:

const sql = 'UPDATE users SET fname = ?, email = ? WHERE id = ?';
await pool.query(sql, ['Jane', 'jane@example.com', 1]);
javascript

DELETE - ลบข้อมูล#

ลบข้อมูล:

DELETE FROM users WHERE id = 3;
sql

ใน JavaScript:

await pool.query('DELETE FROM users WHERE id = ?', [3]);
javascript

JOIN - เชื่อมตาราง#

LEFT JOIN - เชื่อมตารางและแสดงข้อมูลฝั่งซ้ายทั้งหมด:

SELECT users.fname, orders.id
FROM users
LEFT JOIN orders ON users.id = orders.user_id;
sql

ใช้ JOIN หลายตาราง:

SELECT o.id, u.fname, p.name, p.price
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN order_product op ON o.id = op.order_id
JOIN products p ON op.product_id = p.id;
sql

Parameterized Queries (?)#

ทำไมต้องใช้ ??

  • ปลอดภัย - ป้องกัน SQL Injection
  • สะอาด - โค้ดอ่านง่ายขึ้น
  • ถูกต้อง - จัดการ data types ให้อัตโนมัติ

ไม่ดี (เสี่ยง SQL Injection):

const sql = `SELECT * FROM users WHERE id = ${userId}`;
// ถ้า userId = "1; DROP TABLE users;" จะเกิดอันตราย
javascript

ดี (ปลอดภัย):

const sql = 'SELECT * FROM users WHERE id = ?';
await pool.query(sql, [userId]);
// ตัว ? จะถูกแทนที่ด้วยค่าที่ปลอดภัย
javascript

8. สร้าง index.js พร้อม Express + MySQL Endpoints#

สร้างไฟล์ index.js ใน root project และเพิ่มโค้ดพื้นฐานของ Express server พร้อมกับ database connection ที่เราสร้างไว้:

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const pool = require('./src/db'); // Import database connection
const app = express();
const port = 5000; // Define port

// Middleware
app.use(cors());
app.use(bodyParser.json());

// Test route
app.get('/', (req, res) => {
  res.send('Hello! RESTful API is ready to use with MySQL');
});

// Add API endpoints below this line

// Start server
app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
javascript

เริ่มต้นและทดสอบ API Server:

node index.js
bash

เปิดเว็บเบราว์เซอร์ไปที่ http://localhost:5000 จะเห็นข้อความ “Hello! RESTful API is ready to use with MySQL” ดังรูป ตัวอย่างผลลัพธ์ที่ได้จาก API

ต่อไปจะเป็นการเพิ่ม endpoints สำหรับ User, Product และ Order โดยใช้ SQL queries ในการจัดการข้อมูล


8.1. User Endpoints#

เพิ่มโค้ดต่อไปนี้ในไฟล์ index.js ใต้ app.get('/')

// User Endpoints
// Read All Users
app.get('/users', async (req, res) => {
  try {
    const [rows] = await pool.query('SELECT * FROM users');
    res.json(rows);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching users', error: error.message });
  }
});

// Read One User
app.get('/users/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
    if (rows.length === 0) {
      return res.status(404).json({ message: 'User not found' });
    }
    res.json(rows[0]);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching user', error: error.message });
  }
});

// Create User
app.post('/users', async (req, res) => {
  try {
    const { fname, lname, username, email, avatar } = req.body;
    const sql = 'INSERT INTO users (fname, lname, username, email, avatar) VALUES (?, ?, ?, ?, ?)';
    const [result] = await pool.query(sql, [fname, lname, username, email, avatar || null]);

    const [newUser] = await pool.query('SELECT * FROM users WHERE id = ?', [result.insertId]);
    res.status(201).json(newUser[0]);
  } catch (error) {
    if (error.code === 'ER_DUP_ENTRY') {
      return res.status(409).json({ message: 'Username or email already exists' });
    }
    res.status(500).json({ message: 'Error creating user', error: error.message });
  }
});

// Update User
app.put('/users/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const { fname, lname, username, email, avatar } = req.body;

    // Check if user exists
    const [existing] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
    if (existing.length === 0) {
      return res.status(404).json({ message: 'User not found' });
    }

    const sql = 'UPDATE users SET fname = ?, lname = ?, username = ?, email = ?, avatar = ? WHERE id = ?';
    await pool.query(sql, [fname, lname, username, email, avatar || null, id]);

    const [updated] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
    res.status(200).json(updated[0]);
  } catch (error) {
    if (error.code === 'ER_DUP_ENTRY') {
      return res.status(409).json({ message: 'Username or email already exists' });
    }
    res.status(500).json({ message: 'Error updating user', error: error.message });
  }
});

// Delete User
app.delete('/users/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);

    // Check if user exists
    const [existing] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
    if (existing.length === 0) {
      return res.status(404).json({ message: 'User not found' });
    }

    await pool.query('DELETE FROM users WHERE id = ?', [id]);
    res.status(200).json({ message: `User with ID ${id} deleted successfully` });
  } catch (error) {
    res.status(500).json({ message: 'Error deleting user', error: error.message });
  }
});
javascript

คำอธิบาย SQL ใน User Endpoints:

  1. SELECT * FROM users

    • ดึงข้อมูลทุกคอลัมน์จากตาราง users
    • ผลลัพธ์: รายการ users ทั้งหมด
  2. SELECT * FROM users WHERE id = ?

    • ดึงข้อมูล user ที่มี id ตรงกับค่าที่ระบุ
    • ? คือ placeholder ที่จะถูกแทนที่ด้วยค่าจาก array [id]
    • ผลลัพธ์: user 1 คน หรือ empty array ถ้าไม่พบ
  3. INSERT INTO users (…) VALUES (?, ?, ?, ?, ?)

    • เพิ่มข้อมูล user ใหม่
    • result.insertId คือ id ที่ถูกสร้างอัตโนมัติ
    • หลังจาก INSERT ให้ SELECT อีกครั้งเพื่อดึงข้อมูลที่เพิ่งสร้าง
  4. UPDATE users SET … WHERE id = ?

    • อัปเดตข้อมูล user ที่มี id ตรงกับค่าที่ระบุ
    • หลังจาก UPDATE ให้ SELECT เพื่อดึงข้อมูลที่อัปเดตแล้ว
  5. DELETE FROM users WHERE id = ?

    • ลบข้อมูล user ที่มี id ตรงกับค่าที่ระบุ
    • ข้อมูลในตาราง orders จะถูกลบด้วย (CASCADE)

Error Handling:

  • ER_DUP_ENTRY - เกิดเมื่อข้อมูลซ้ำ (username หรือ email ซ้ำ)
  • rows.length === 0 - ไม่พบข้อมูล
HTTP MethodURIวัตถุประสงค์LogicResponse
GET/usersดึงข้อมูลผู้ใช้ทั้งหมดใช้ SELECT * FROM users เพื่อดึงข้อมูลทั้งหมดรายการของ Object ผู้ใช้ทั้งหมด
GET/users/:idดึงข้อมูลผู้ใช้ตาม IDใช้ SELECT WHERE id = ? จาก URL parameter id หากไม่พบจะคืนค่า 404Object ผู้ใช้ หรือ 404 (ไม่พบ)
POST/usersสร้างผู้ใช้ใหม่req.body ควรมี fname, lname, username, email, avatar ใช้ INSERT INTO usersObject ผู้ใช้ที่สร้างใหม่ หรือ 409 (ซ้ำ) หรือ 500 (ข้อผิดพลาด)
PUT/users/:idอัปเดตผู้ใช้ตาม IDอัปเดตข้อมูลผู้ใช้โดยใช้ ID จาก URL และข้อมูลจาก Body จัดการข้อผิดพลาด (เช่น ไม่พบผู้ใช้ หรือข้อมูลซ้ำ)Object ผู้ใช้ที่อัปเดต หรือ 404 (ไม่พบ) หรือ 409 (ซ้ำ) หรือ 500 (ข้อผิดพลาด)
DELETE/users/:idลบผู้ใช้ตาม IDใช้ DELETE FROM users WHERE id = ? ด้วย ID ที่กำหนดข้อความยืนยันการลบ หรือ 404 (ไม่พบ) หรือ 500 (ข้อผิดพลาด)

ตัวอย่างการทดสอบ API POST /users

วัตถุประสงค์ สร้างผู้ใช้ใหม่

Logic

  • req.body ต้องประกอบด้วยข้อมูลต่อไปนี้: fname (ชื่อจริง), lname (นามสกุล), username (ชื่อผู้ใช้), email (อีเมล), และ avatar (รูปโปรไฟล์)
  • ระบบจะใช้คำสั่ง INSERT INTO users เพื่อบันทึกข้อมูลผู้ใช้ลงในฐานข้อมูล

Response อ็อบเจกต์ของข้อมูลผู้ใช้ที่ถูกสร้างขึ้นมาใหม่ ตัวอย่างการทดสอบ API POST /users

ตัวอย่างการทดสอบ API GET /users

วัตถุประสงค์ ดึงข้อมูลผู้ใช้ทั้งหมด

Logic

  • ระบบจะใช้คำสั่ง SELECT * FROM users เพื่อเรียกดูข้อมูลผู้ใช้ทั้งหมดจากฐานข้อมูล

Response รายการอ็อบเจกต์ของข้อมูลผู้ใช้ทั้งหมด ตัวอย่างการทดสอบ API GET /users

ตัวอย่างการทดสอบ API GET /users/:id

วัตถุประสงค์ ดึงข้อมูลผู้ใช้รายเดียวด้วย ID

Logic

  • ระบบจะใช้คำสั่ง SELECT WHERE id = ? โดยใช้ค่า id ที่ได้จากพารามิเตอร์ใน URL
  • หากไม่พบผู้ใช้ ระบบจะส่งคืนสถานะ 404 (Not Found)

Response อ็อบเจกต์ของข้อมูลผู้ใช้เพียงรายเดียว

ตัวอย่างการทดสอบ API GET /users/:id ตัวอย่างการทดสอบ API GET /users/:id

ตัวอย่างการทดสอบ API GET /users/:id แบบไม่พบ user ตัวอย่างการทดสอบ API GET /users/:id แบบไม่พบ user

ตัวอย่างการทดสอบ API PUT /users/:id

วัตถุประสงค์ อัปเดตข้อมูลผู้ใช้ด้วย ID

Logic

  • ระบบจะแยกวิเคราะห์ (parse) ค่า id จาก URL
  • ใช้คำสั่ง UPDATE users SET … WHERE id = ? พร้อมข้อมูลใหม่ที่ต้องการอัปเดต
  • มีการดักจับข้อผิดพลาด (error handling) เช่น กรณีที่ไม่พบผู้ใช้

Response อ็อบเจกต์ของข้อมูลผู้ใช้ที่ได้รับการอัปเดตแล้ว

ตัวอย่างการทดสอบ API PUT /users/:id

ตัวอย่างการทดสอบ API DELETE /users/:id

วัตถุประสงค์ ลบผู้ใช้ด้วย ID

Logic

  • ระบบจะใช้คำสั่ง DELETE FROM users WHERE id = ? โดยใช้ค่า ID ที่ระบุ

Response ข้อความยืนยันการลบผู้ใช้

ตัวอย่างการทดสอบ API DELETE /users/:id

8.2. Product Endpoints#

เพิ่มโค้ดต่อไปนี้ในไฟล์ index.js

// Product Endpoints
// Read All Products
app.get('/products', async (req, res) => {
  try {
    const [rows] = await pool.query('SELECT * FROM products');
    res.json(rows);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching products', error: error.message });
  }
});

// Read One Product
app.get('/products/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const [rows] = await pool.query('SELECT * FROM products WHERE id = ?', [id]);
    if (rows.length === 0) {
      return res.status(404).json({ message: 'Product not found' });
    }
    res.json(rows[0]);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching product', error: error.message });
  }
});

// Create Product
app.post('/products', async (req, res) => {
  try {
    const { name, price } = req.body;
    const sql = 'INSERT INTO products (name, price) VALUES (?, ?)';
    const [result] = await pool.query(sql, [name, price]);

    const [newProduct] = await pool.query('SELECT * FROM products WHERE id = ?', [result.insertId]);
    res.status(201).json(newProduct[0]);
  } catch (error) {
    res.status(500).json({ message: 'Error creating product', error: error.message });
  }
});

// Update Product
app.put('/products/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const { name, price } = req.body;

    // Check if product exists
    const [existing] = await pool.query('SELECT * FROM products WHERE id = ?', [id]);
    if (existing.length === 0) {
      return res.status(404).json({ message: 'Product not found' });
    }

    const sql = 'UPDATE products SET name = ?, price = ? WHERE id = ?';
    await pool.query(sql, [name, price, id]);

    const [updated] = await pool.query('SELECT * FROM products WHERE id = ?', [id]);
    res.status(200).json(updated[0]);
  } catch (error) {
    res.status(500).json({ message: 'Error updating product', error: error.message });
  }
});

// Delete Product
app.delete('/products/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);

    // Check if product exists
    const [existing] = await pool.query('SELECT * FROM products WHERE id = ?', [id]);
    if (existing.length === 0) {
      return res.status(404).json({ message: 'Product not found' });
    }

    await pool.query('DELETE FROM products WHERE id = ?', [id]);
    res.status(200).json({ message: `Product with ID ${id} deleted successfully` });
  } catch (error) {
    res.status(500).json({ message: 'Error deleting product', error: error.message });
  }
});
javascript
HTTP MethodURIวัตถุประสงค์LogicResponse
GET/productsดึงข้อมูลสินค้าทั้งหมดใช้ SELECT * FROM products เพื่อดึงข้อมูลทั้งหมดรายการของ Object สินค้าทั้งหมด
GET/products/:idดึงข้อมูลสินค้าตาม IDใช้ SELECT WHERE id = ? จาก URL parameter id หากไม่พบจะคืนค่า 404Object สินค้า หรือ 404 (ไม่พบ)
POST/productsสร้างสินค้าใหม่req.body ควรมีข้อมูลสินค้า ใช้ INSERT INTO productsObject สินค้าที่สร้างใหม่ หรือ 500 (ข้อผิดพลาด)
PUT/products/:idอัปเดตสินค้าตาม IDอัปเดตข้อมูลสินค้าโดยใช้ ID จาก URL และข้อมูลจาก Body จัดการข้อผิดพลาด (เช่น ไม่พบสินค้า)Object สินค้าที่อัปเดต หรือ 404 (ไม่พบ) หรือ 500 (ข้อผิดพลาด)
DELETE/products/:idลบสินค้าตาม IDใช้ DELETE FROM products WHERE id = ? ด้วย ID ที่กำหนดข้อความยืนยันการลบ หรือ 404 (ไม่พบ) หรือ 500 (ข้อผิดพลาด)

ตัวอย่างการทดสอบ API POST /products

วัตถุประสงค์ สร้างสินค้าใหม่

Logic

  • req.body ต้องประกอบด้วยข้อมูลสินค้า
  • ระบบจะใช้คำสั่ง INSERT INTO products เพื่อบันทึกข้อมูลสินค้าลงในฐานข้อมูล

Response อ็อบเจกต์ของข้อมูลสินค้าที่ถูกสร้างขึ้นมาใหม่

ตัวอย่างการทดสอบ API POST /products

ตัวอย่างการทดสอบ API GET /products

วัตถุประสงค์ ดึงข้อมูลสินค้าทั้งหมด

Logic

  • ระบบจะใช้คำสั่ง SELECT * FROM products เพื่อเรียกดูข้อมูลสินค้าทั้งหมดจากฐานข้อมูล

Response รายการอ็อบเจกต์ของข้อมูลสินค้าทั้งหมด

ตัวอย่างการทดสอบ API GET /products

ตัวอย่างการทดสอบ API GET /products/:id

วัตถุประสงค์ ดึงข้อมูลสินค้ารายเดียวด้วย ID

Logic

  • ระบบจะใช้คำสั่ง SELECT WHERE id = ? โดยใช้ค่า id ที่ได้จากพารามิเตอร์ใน URL
  • หากไม่พบสินค้า ระบบจะส่งคืนสถานะ 404 (Not Found)

Response อ็อบเจกต์ของข้อมูลสินค้าเพียงรายเดียว

ตัวอย่างการทดสอบ API GET /products/:id

ตัวอย่างการทดสอบ API PUT /products/:id

วัตถุประสงค์ อัปเดตข้อมูลสินค้าด้วย ID

Logic

  • ระบบจะแยกวิเคราะห์ (parse) ค่า id จาก URL
  • ใช้คำสั่ง UPDATE products SET … WHERE id = ? พร้อมข้อมูลใหม่ที่ต้องการอัปเดต
  • มีการดักจับข้อผิดพลาด (error handling) เช่น กรณีที่ไม่พบสินค้า

Response อ็อบเจกต์ของข้อมูลสินค้าที่ได้รับการอัปเดตแล้ว

ตัวอย่างการทดสอบ API PUT /products/:id

ตัวอย่างการทดสอบ API DELETE /products/:id

วัตถุประสงค์ ลบสินค้าด้วย ID

Logic

  • ระบบจะใช้คำสั่ง DELETE FROM products WHERE id = ? โดยใช้ค่า ID ที่ระบุ

Response ข้อความยืนยันการลบสินค้า

ตัวอย่างการทดสอบ API DELETE /products/:id

8.3. Order Endpoints#

เพิ่มโค้ดต่อไปนี้ในไฟล์ index.js

// Order Endpoints
// Read All Orders
app.get('/orders', async (req, res) => {
  try {
    const [orders] = await pool.query(`
      SELECT
        o.id,
        o.user_id,
        o.created_at,
        u.id as user_id,
        u.fname,
        u.lname,
        u.username,
        u.email,
        u.avatar
      FROM orders o
      JOIN users u ON o.user_id = u.id
    `);

    // Get products for each order
    for (const order of orders) {
      const [products] = await pool.query(`
        SELECT p.*
        FROM products p
        JOIN order_product op ON p.id = op.product_id
        WHERE op.order_id = ?
      `, [order.id]);
      order.products = products;
      order.user = {
        id: order.user_id,
        fname: order.fname,
        lname: order.lname,
        username: order.username,
        email: order.email,
        avatar: order.avatar
      };
      delete order.fname;
      delete order.lname;
      delete order.username;
      delete order.email;
      delete order.avatar;
    }

    res.json(orders);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching orders', error: error.message });
  }
});

// Read One Order
app.get('/orders/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);
    const [orders] = await pool.query(`
      SELECT
        o.id,
        o.user_id,
        o.created_at,
        u.fname,
        u.lname,
        u.username,
        u.email,
        u.avatar
      FROM orders o
      JOIN users u ON o.user_id = u.id
      WHERE o.id = ?
    `, [id]);

    if (orders.length === 0) {
      return res.status(404).json({ message: 'Order not found' });
    }

    const order = orders[0];

    // Get products for the order
    const [products] = await pool.query(`
      SELECT p.*
      FROM products p
      JOIN order_product op ON p.id = op.product_id
      WHERE op.order_id = ?
    `, [id]);

    order.products = products;
    order.user = {
      id: order.user_id,
      fname: order.fname,
      lname: order.lname,
      username: order.username,
      email: order.email,
      avatar: order.avatar
    };
    delete order.fname;
    delete order.lname;
    delete order.username;
    delete order.email;
    delete order.avatar;

    res.json(order);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching order', error: error.message });
  }
});

// Create Order
app.post('/orders', async (req, res) => {
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();
    const { userId, productIds } = req.body;

    // Check if user exists
    const [users] = await connection.query('SELECT * FROM users WHERE id = ?', [userId]);
    if (users.length === 0) {
      await connection.rollback();
      return res.status(400).json({ message: 'Invalid user ID' });
    }

    // Create order
    const [orderResult] = await connection.query('INSERT INTO orders (user_id) VALUES (?)', [userId]);
    const orderId = orderResult.insertId;

    // Add products to order
    for (const productId of productIds) {
      await connection.query('INSERT INTO order_product (order_id, product_id) VALUES (?, ?)', [orderId, productId]);
    }

    await connection.commit();

    // Get complete order data
    const [orders] = await pool.query(`
      SELECT
        o.id,
        o.user_id,
        o.created_at,
        u.fname,
        u.lname,
        u.username,
        u.email,
        u.avatar
      FROM orders o
      JOIN users u ON o.user_id = u.id
      WHERE o.id = ?
    `, [orderId]);

    const [products] = await pool.query(`
      SELECT p.*
      FROM products p
      JOIN order_product op ON p.id = op.product_id
      WHERE op.order_id = ?
    `, [orderId]);

    const order = orders[0];
    order.products = products;
    order.user = {
      id: order.user_id,
      fname: order.fname,
      lname: order.lname,
      username: order.username,
      email: order.email,
      avatar: order.avatar
    };
    delete order.fname;
    delete order.lname;
    delete order.username;
    delete order.email;
    delete order.avatar;

    res.status(201).json(order);
  } catch (error) {
    await connection.rollback();
    if (error.code === 'ER_NO_REFERENCED_ROW_2') {
      return res.status(400).json({ message: 'Invalid user ID or product ID' });
    }
    res.status(500).json({ message: 'Error creating order', error: error.message });
  } finally {
    connection.release();
  }
});

// Update Order
app.put('/orders/:id', async (req, res) => {
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();
    const id = parseInt(req.params.id);
    const { userId, productIds } = req.body;

    // Check if order exists
    const [existing] = await connection.query('SELECT * FROM orders WHERE id = ?', [id]);
    if (existing.length === 0) {
      await connection.rollback();
      return res.status(404).json({ message: 'Order not found' });
    }

    // Update order user
    await connection.query('UPDATE orders SET user_id = ? WHERE id = ?', [userId, id]);

    // Delete old products and add new ones
    await connection.query('DELETE FROM order_product WHERE order_id = ?', [id]);
    for (const productId of productIds) {
      await connection.query('INSERT INTO order_product (order_id, product_id) VALUES (?, ?)', [id, productId]);
    }

    await connection.commit();

    // Get complete order data
    const [orders] = await pool.query(`
      SELECT
        o.id,
        o.user_id,
        o.created_at,
        u.fname,
        u.lname,
        u.username,
        u.email,
        u.avatar
      FROM orders o
      JOIN users u ON o.user_id = u.id
      WHERE o.id = ?
    `, [id]);

    const [products] = await pool.query(`
      SELECT p.*
      FROM products p
      JOIN order_product op ON p.id = op.product_id
      WHERE op.order_id = ?
    `, [id]);

    const order = orders[0];
    order.products = products;
    order.user = {
      id: order.user_id,
      fname: order.fname,
      lname: order.lname,
      username: order.username,
      email: order.email,
      avatar: order.avatar
    };
    delete order.fname;
    delete order.lname;
    delete order.username;
    delete order.email;
    delete order.avatar;

    res.status(200).json(order);
  } catch (error) {
    await connection.rollback();
    if (error.code === 'ER_NO_REFERENCED_ROW_2') {
      return res.status(400).json({ message: 'Invalid user ID or product ID' });
    }
    res.status(500).json({ message: 'Error updating order', error: error.message });
  } finally {
    connection.release();
  }
});

// Delete Order
app.delete('/orders/:id', async (req, res) => {
  try {
    const id = parseInt(req.params.id);

    // Check if order exists
    const [existing] = await pool.query('SELECT * FROM orders WHERE id = ?', [id]);
    if (existing.length === 0) {
      return res.status(404).json({ message: 'Order not found' });
    }

    // Delete related order_product records (will be auto-deleted by CASCADE)
    await pool.query('DELETE FROM orders WHERE id = ?', [id]);
    res.status(200).json({ message: `Order with ID ${id} deleted successfully` });
  } catch (error) {
    res.status(500).json({ message: 'Error deleting order', error: error.message });
  }
});
javascript

คำอธิบาย SQL JOIN ใน Order Endpoints:

1. JOIN เพื่อดึงข้อมูลคำสั่งซื้อพร้อมผู้ใช้:

SELECT
  o.id, o.user_id, o.created_at,
  u.fname, u.lname, u.username, u.email, u.avatar
FROM orders o
JOIN users u ON o.user_id = u.id
sql
  • o และ u คือ alias (ชื่อย่อ) ของตาราง
  • JOIN users u ON o.user_id = u.id เชื่อมตาราง orders กับ users
  • ผลลัพธ์: คำสั่งซื้อพร้อมข้อมูลผู้ใช้

2. JOIN เพื่อดึงสินค้าในคำสั่งซื้อ:

SELECT p.*
FROM products p
JOIN order_product op ON p.id = op.product_id
WHERE op.order_id = ?
sql
  • เชื่อมตาราง products กับ order_product
  • กรองเฉพาะสินค้าที่อยู่ในคำสั่งซื้อที่ระบุ

3. Transaction สำหรับ CREATE/UPDATE:

const connection = await pool.getConnection();
try {
  await connection.beginTransaction();
  // หลายคำสั่ง SQL
  await connection.commit();
} catch (error) {
  await connection.rollback();
}
javascript
  • Transaction ใช้เมื่อต้องทำหลายคำสั่งให้สำเร็จทั้งหมด
  • commit - ยืนยันการเปลี่ยนแปลง
  • rollback - ยกเลิกการเปลี่ยนแปลงถ้าเกิดข้อผิดพลาด

4. INSERT พร้อมการเชื่อมโยง:

INSERT INTO orders (user_id) VALUES (?);           -- สร้างคำสั่งซื้อ
INSERT INTO order_product (order_id, product_id)   -- เชื่อมสินค้า
VALUES (?, ?);
sql

5. DELETE พร้อม CASCADE:

DELETE FROM orders WHERE id = ?
-- ข้อมูลใน order_product จะถูกลบอัตโนมัติ (CASCADE)
sql
HTTP MethodURIวัตถุประสงค์LogicResponse
GET/ordersดึงข้อมูลคำสั่งซื้อทั้งหมดใช้ JOIN เพื่อดึงข้อมูลคำสั่งซื้อพร้อมผู้ใช้และสินค้ารายการของ Object คำสั่งซื้อทั้งหมดพร้อมข้อมูลผู้ใช้และสินค้า
GET/orders/:idดึงข้อมูลคำสั่งซื้อตาม IDใช้ JOIN WHERE id = ? พร้อมข้อมูลสินค้า หากไม่พบจะคืนค่า 404Object คำสั่งซื้อพร้อมข้อมูลผู้ใช้และสินค้า หรือ 404 (ไม่พบ)
POST/ordersสร้างคำสั่งซื้อใหม่req.body ต้องมี userId และ productIds ใช้ Transaction และ INSERT พร้อมสร้างความสัมพันธ์กับสินค้าObject คำสั่งซื้อที่สร้างใหม่พร้อมข้อมูลผู้ใช้และสินค้า หรือ 400 (ข้อมูลไม่ถูกต้อง) หรือ 500 (ข้อผิดพลาด)
PUT/orders/:idอัปเดตคำสั่งซื้อตาม IDอัปเดตข้อมูลคำสั่งซื้อ ลบสินค้าเก่าและเพิ่มสินค้าใหม่ จัดการข้อผิดพลาดObject คำสั่งซื้อที่อัปเดตพร้อมข้อมูลผู้ใช้และสินค้า หรือ 404 (ไม่พบ) หรือ 400 (ข้อมูลไม่ถูกต้อง) หรือ 500 (ข้อผิดพลาด)
DELETE/orders/:idลบคำสั่งซื้อตาม IDลบคำสั่งซื้อ (ข้อมูลใน order_product จะถูกลบโดย CASCADE)ข้อความยืนยันการลบ หรือ 404 (ไม่พบ) หรือ 500 (ข้อผิดพลาด)

ตัวอย่างการทดสอบ API POST /orders

วัตถุประสงค์ สร้างคำสั่งซื้อใหม่

Logic

  • req.body ต้องประกอบด้วยข้อมูลต่อไปนี้: userId (รหัสผู้ใช้) และ productIds (รายการรหัสสินค้า)
  • ระบบจะใช้คำสั่ง INSERT INTO orders และ INSERT INTO order_product พร้อม Transaction เพื่อสร้างคำสั่งซื้อและเชื่อมโยงกับสินค้าที่เลือก
  • ข้อมูลจะถูกส่งกลับพร้อมข้อมูลผู้ใช้และรายละเอียดสินค้า

Response อ็อบเจกต์ของข้อมูลคำสั่งซื้อที่ถูกสร้างขึ้นมาใหม่พร้อมข้อมูลผู้ใช้และสินค้า

ตัวอย่างการทดสอบ API POST /orders

ตัวอย่างการทดสอบ API GET /orders

วัตถุประสงค์ ดึงข้อมูลคำสั่งซื้อทั้งหมด

Logic

  • ระบบจะใช้คำสั่ง JOIN เพื่อดึงข้อมูลคำสั่งซื้อทั้งหมดพร้อมข้อมูลผู้ใช้และสินค้า

Response รายการอ็อบเจกต์ของข้อมูลคำสั่งซื้อทั้งหมดพร้อมข้อมูลผู้ใช้และสินค้า

ตัวอย่างการทดสอบ API GET /orders

ตัวอย่างการทดสอบ API GET /orders/:id

วัตถุประสงค์ ดึงข้อมูลคำสั่งซื้อรายเดียวด้วย ID

Logic

  • ระบบจะใช้คำสั่ง JOIN WHERE id = ? โดยใช้ค่า id ที่ได้จากพารามิเตอร์ใน URL
  • ใช้ JOIN เพื่อดึงข้อมูลผู้ใช้และสินค้าที่เกี่ยวข้อง
  • หากไม่พบคำสั่งซื้อ ระบบจะส่งคืนสถานะ 404 (Not Found)

Response อ็อบเจกต์ของข้อมูลคำสั่งซื้อเพียงรายเดียวพร้อมข้อมูลผู้ใช้และสินค้า

ตัวอย่างการทดสอบ API GET /orders/:id

ตัวอย่างการทดสอบ API PUT /orders/:id

วัตถุประสงค์ อัปเดตข้อมูลคำสั่งซื้อด้วย ID

Logic

  • ระบบจะแยกวิเคราะห์ (parse) ค่า id จาก URL
  • ใช้คำสั่ง UPDATE orders และ DELETE/INSERT order_product พร้อมข้อมูลใหม่ใน Transaction
  • ลบความสัมพันธ์กับสินค้าเก่าทั้งหมด และสร้างความสัมพันธ์ใหม่กับสินค้าที่เลือก
  • มีการดักจับข้อผิดพลาด (error handling) เช่น กรณีที่ไม่พบคำสั่งซื้อ

Response อ็อบเจกต์ของข้อมูลคำสั่งซื้อที่ได้รับการอัปเดตแล้วพร้อมข้อมูลผู้ใช้และสินค้า

ตัวอย่างการทดสอบ API PUT /orders/:id

ตัวอย่างการทดสอบ API DELETE /orders/:id

วัตถุประสงค์ ลบคำสั่งซื้อด้วย ID

Logic

  • ระบบจะใช้คำสั่ง DELETE FROM orders WHERE id = ?
  • ข้อมูลในตาราง order_product จะถูกลบอัตโนมัติโดย CASCADE

Response ข้อความยืนยันการลบคำสั่งซื้อ

ตัวอย่างการทดสอบ API DELETE /orders/:id |

8.4. Nested Endpoints#

เพิ่มโค้ดต่อไปนี้ในไฟล์ index.js เพื่อสร้าง endpoints สำหรับทรัพยากรแบบซ้อน

// Relationship Endpoints
// Get Orders by User ID
app.get('/users/:id/orders', async (req, res) => {
  const id = parseInt(req.params.id);
  try {
    // Check if user exists
    const [users] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
    if (users.length === 0) {
      return res.status(404).json({ message: 'User not found' });
    }

    const [orders] = await pool.query(`
      SELECT
        o.id,
        o.user_id,
        o.created_at,
        u.fname,
        u.lname,
        u.username,
        u.email,
        u.avatar
      FROM orders o
      JOIN users u ON o.user_id = u.id
      WHERE o.user_id = ?
    `, [id]);

    // Get products for each order
    for (const order of orders) {
      const [products] = await pool.query(`
        SELECT p.*
        FROM products p
        JOIN order_product op ON p.id = op.product_id
        WHERE op.order_id = ?
      `, [order.id]);
      order.products = products;
      order.user = {
        id: order.user_id,
        fname: order.fname,
        lname: order.lname,
        username: order.username,
        email: order.email,
        avatar: order.avatar
      };
      delete order.fname;
      delete order.lname;
      delete order.username;
      delete order.email;
      delete order.avatar;
    }

    res.json(orders);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching user orders', error: error.message });
  }
});

// Get Products by Order ID
app.get('/orders/:id/products', async (req, res) => {
  const id = parseInt(req.params.id);
  try {
    // Check if order exists
    const [orders] = await pool.query('SELECT * FROM orders WHERE id = ?', [id]);
    if (orders.length === 0) {
      return res.status(404).json({ message: 'Order not found' });
    }

    const [products] = await pool.query(`
      SELECT p.*
      FROM products p
      JOIN order_product op ON p.id = op.product_id
      WHERE op.order_id = ?
    `, [id]);

    res.json(products);
  } catch (error) {
    res.status(500).json({ message: 'Error fetching order products', error: error.message });
  }
});
javascript
HTTP MethodURIวัตถุประสงค์LogicResponse
GET/users/:id/ordersดึงคำสั่งซื้อทั้งหมดของผู้ใช้ตรวจสอบว่าผู้ใช้มีอยู่จริง จากนั้นใช้ JOIN WHERE user_id = ?รายการ Object คำสั่งซื้อของผู้ใช้นั้นๆ พร้อมข้อมูลสินค้า หรือ 404 (ไม่พบผู้ใช้) หรือ 500 (ข้อผิดพลาด)
GET/orders/:id/productsดึงสินค้าทั้งหมดในคำสั่งซื้อใช้ JOIN เพื่อหาคำสั่งซื้อพร้อมสินค้า จากนั้นคืนค่าเฉพาะข้อมูลสินค้ารายการ Object สินค้าในคำสั่งซื้อนั้นๆ หรือ 404 (ไม่พบคำสั่งซื้อ) หรือ 500 (ข้อผิดพลาด)

ตัวอย่างการทดสอบ API GET /users/:id/orders

วัตถุประสงค์ ดึงข้อมูลคำสั่งซื้อทั้งหมดของผู้ใช้คนหนึ่ง

Logic

  • ระบบจะตรวจสอบว่าผู้ใช้ที่มี id ตามที่ระบุมีอยู่ในฐานข้อมูลหรือไม่
  • หากพบผู้ใช้ ระบบจะใช้คำสั่ง JOIN WHERE user_id = ? โดยกรองด้วย user_id
  • ใช้ JOIN เพื่อดึงข้อมูลสินค้าและผู้ใช้ที่เกี่ยวข้อง
  • หากไม่พบผู้ใช้ ระบบจะส่งคืนสถานะ 404 (User not found)

Response รายการอ็อบเจกต์ของคำสั่งซื้อทั้งหมดของผู้ใช้นั้นๆ พร้อมข้อมูลสินค้า

ตัวอย่างการทดสอบ API GET /users/:id/orders

ตัวอย่างการทดสอบ API GET /orders/:id/products

วัตถุประสงค์ ดึงข้อมูลสินค้าทั้งหมดในคำสั่งซื้อหนึ่งๆ

Logic

  • ระบบจะใช้คำสั่ง JOIN โดยใช้ค่า id ของคำสั่งซื้อที่ได้จากพารามิเตอร์ใน URL
  • ใช้ JOIN เพื่อดึงข้อมูลสินค้าที่เกี่ยวข้องกับคำสั่งซื้อ
  • หากไม่พบคำสั่งซื้อ ระบบจะส่งคืนสถานะ 404 (Order not found)

Response รายการอ็อบเจกต์ของสินค้าทั้งหมดที่อยู่ในคำสั่งซื้อนั้นๆ

ตัวอย่างการทดสอบ API GET /orders/:id/products

หมายเหตุเพิ่มเติม

Relationship Endpoints เหล่านี้ช่วยให้การเข้าถึงข้อมูลที่เกี่ยวข้องกันมีความสะดวกมากขึ้น:

  • /users/:id/orders - เหมาะสำหรับการแสดงประวัติการสั่งซื้อของลูกค้าแต่ละคน
  • /orders/:id/products - เหมาะสำหรับการแสดงรายการสินค้าในใบสั่งซื้อเฉพาะ

ทั้งสอง endpoints นี้ช่วยลดความซับซ้อนในการเรียกใช้ข้อมูลจากฝั่ง frontend และทำให้ API มีความยืดหยุ่นในการใช้งานมากขึ้น

การทำความเข้าใจโครงสร้าง API และการเขียน SQL queries โดยตรงจะช่วยให้เข้าใจหลักการพัฒนา Web Application และการจัดการฐานข้อมูลได้ดีมากขึ้นครับ

พื้นฐานการพัฒนา RESTful API ด้วย Node.js, Express และ MySQL
ผู้เขียน กานต์ ยงศิริวิทย์ / Karn Yongsiriwit
เผยแพร่เมื่อ February 10, 2027
ลิขสิทธิ์ CC BY-NC-SA 4.0

กำลังโหลดความคิดเห็น...

ความคิดเห็น 0