Skip to main content

นำ Rest API ต่อกับ MySQL

ทวนโจทย์ใน API เดิมของเรา (จากบทที่ 9) เราได้สร้างมาทั้งหมด 5 paths ตามนี้

  1. GET /users สำหรับ get users ทั้งหมดที่บันทึกเข้าไปออกมา
  2. POST /users สำหรับการสร้าง users ใหม่บันทึกเข้าไป
  3. GET /users/:id สำหรับการดึง users รายคนออกมา
  4. PUT /users/:id สำหรับการแก้ไข users รายคน (ตาม id ที่บันทึกเข้าไป)
  5. DELETE /users/:id สำหรับการลบ users รายคน (ตาม id ที่บันทึกเข้าไป)

เราจะนำทั้ง 5 path นี้ต่อเข้ากับ mysql จริงๆออกมา

  • แต่เพื่อให้ code การต่อ mysql อำนวยความสะดวกยิ่งขึ้น เราจะทำการสร้าง function เพื่อทำการ connect mysql เอาไว้ก่อน และเราจะเปลี่ยนแค่ code ตรงกลางเท่านั้น
  • ทำการลบตัวแปร users, counter ออก เนื่องจากเราจะเปลี่ยนจาก Mock เป็นการต่อฐานข้อมูลแล้ว (ไม่ได้ใช้แล้ว)
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const mysql = require('mysql2/promise')

app.use(bodyParser.json())

let conn = null

// function connectMySQL
const connectMySQL = async () => {
conn = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'yourdb'
})
}

/* เปลี่ยนแค่ code ตรงนี้ */

app.listen(8000, async () => {
// เรียกใช้ connectMySQL ตอน start server
await connectMySQL()
console.log('Server started on port 8000')
})

เดี๋ยวเราจะมาเรียนรู้ไปพร้อมกัน 2 เรื่อง

  1. การทำตามโจทย์ของ API
  2. การ handle error (ในกรณีเกิดเคสที่ไม่ถูกต้องเกิดขึ้น) ** และเป็น core งานหลักของ Backend

1. GET /users สำหรับ get users ทั้งหมดที่บันทึกเข้าไปออกมา

เพิ่ม

  • ท่า conn.query เป็นท่าที่ใช้สำหรับยิง query
  • results คือ ผลลัพธ์ที่ได้คืนมาจาก conn.query และ results[0] คือ data ที่ได้มาจาก conn.query นั้น
  • ทวน: SELECT * from users คือการดึงข้อมูล users ทั้งหมดและทุก column ออกมา
  • เพิ่ม try, catch สำหรับการ handle error ออกมา ในกรณีที่มีปัญหาในการยิง query
...
app.get('/users', async (req, res) => {
try {
let results = await conn.query('SELECT * FROM users')
res.json(results[0])
} catch (error) {
console.error('Error fetching users:', error.message)
res.status(500).json({ error: 'Error fetching users' })
}
})
...

เพิ่มเติม เหตุผลที่ต้องใช้ result[0]

  • สาเหตุเพราะ library mysql2 ทำไว้แบบนั้นครับ คำสั่ง conn.query มีการ return ผลลัพธ์เป็น array 2 ค่าไว้ครับ (สมมุติชื่อ result)
  1. result[0] เป็นค่าของ rows ทั้งหมดที่ query ออกมาได้
  2. result[1] เป้นค่าของ fields (ชื่อ column) ทั้งหมดที่ query ออกมาได้

ดูเพิ่มเติมได้จากตรง หัวข้อ "Using Promise Wrapper" ในเอกสารของ mysql2 https://www.npmjs.com/package/mysql2#array-results

ตรง

const [rows, fields] = await connection.execute('SELECT * from users')

// ท่านี้เปรียบได้กับ
const rows = result[0]
const fields = result[1]

2. POST /users สำหรับการสร้าง users ใหม่บันทึกเข้าไป

เพิ่ม

  • ทวน: INSERT INTO users SET ? คือท่าสำหรับการ INSERT data โดย สามารถใส่ column='value' ตรงตำแหน่ง ? ได้ (ท่าเพิ่มเติม: https://www.thaicreate.com/tutorial/sql-insert-into-set.html)
  • conn.query('query', [data]) โดย data นั้นคือสิ่งที่จะนำไปใส่ค่าใน query ตามตำแหน่งของ ? (เช่นเคสนี้ จะใส่ data ใส่ตำแหน่ง ?)
...
app.post('/users', async (req, res) => {
const data = req.body

try {
const result = await conn.query('INSERT INTO users SET ?', data)
const userId = result[0].insertId
res.status(201).json({ message: 'User created successfully', userId })
} catch (error) {
console.error('Error creating user:', error.message)
res.status(500).json({ error: 'Error creating user' })
}
})
...

3. GET /users/:id สำหรับการดึง users รายคนออกมา

เพิ่ม

  • ทวน: SELECT * FROM users WHERE id = ? โดย id คือ column ที่ต้องการจะ search และ ? คือ value ที่ต้องการค้นหา
...
app.get('/users/:id', async (req, res) => {
const id = req.params.id

try {
let [results] = await conn.query('SELECT * FROM users WHERE id = ?', [id])
if (results.length === 0) {
return res.status(404).json({ error: 'User not found' })
}
res.json(results[0])
} catch (error) {
console.error('Error fetching user:', error.message)
res.status(500).json({ error: 'Error fetching user' })
}
})
...

4. PUT /users/:id สำหรับการแก้ไข users รายคน (ตาม id ที่บันทึกเข้าไป)

เพิ่ม

  • ทวน: UPDATE users SET ? WHERE id = ? โดย id คือ column ที่ต้องการจะ search และ ? และ ? หลัง SET คือค่าที่ต้องการ update
...
app.put('/users/:id', async (req, res) => {
const id = req.params.id
const data = req.body

try {
const result = await conn.query('UPDATE users SET ? WHERE id = ?', [data, id])
if (result[0].affectedRows === 0) {
return res.status(404).json({ error: 'User not found' })
}
res.json({ message: 'User updated successfully', userId: id })
} catch (error) {
console.error('Error updating user:', error.message)
res.status(500).json({ error: 'Error updating user' })
}
})
...

5. DELETE /users/:id สำหรับการลบ users รายคน (ตาม id ที่บันทึกเข้าไป)

เพิ่ม

  • ทวน: DELETE FROM users SET ? WHERE id = ? โดย id คือ column ที่ต้องการจะ search และ ? และ ? หลัง SET คือค่าที่ต้องการ update
...
app.delete('/users/:id', async (req, res) => {
const id = req.params.id

try {
const result = await conn.query('DELETE FROM users WHERE id = ?', [id])
if (result[0].affectedRows === 0) {
return res.status(404).json({ error: 'User not found' })
}
res.json({ message: 'User deleted successfully', userId: id })
} catch (error) {
console.error('Error deleting user:', error.message)
res.status(500).json({ error: 'Error deleting user' })
}
})
...

Full code ทั้งหมดดูได้ที่นี่ https://github.com/mikelopster/web101/tree/main/sessions/chapter-10