นำ Rest API ต่อกับ MySQL
ทวนโจทย์ใน API เดิมของเรา (จากบทที่ 9) เราได้สร้างมาทั้งหมด 5 paths ตามนี้
GET /users
สำหรับ get users ทั้งหมดที่บันทึกเข้าไปออกมาPOST /users
สำหรับการสร้าง users ใหม่บันทึกเข้าไปGET /users/:id
สำหรับการดึง users รายคนออกมาPUT /users/:id
สำหรับการแก้ไข users รายคน (ตาม id ที่บันทึกเข้าไป)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 เรื่อง
- การทำตามโจทย์ของ API
- การ 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)
- result[0] เป็นค่าของ rows ทั้งหมดที่ query ออกมาได้
- 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' })
}
})
...