Note : บันทึก Workshop สร้าง Website ด้วย Node.js + Vue.js #Part 5

Artdvp
8 min readAug 16, 2018

--

https://knexjs.org/

Step 8— Introduce Knex.js + Express

Knex.js เบื้องต้น

ในที่นี้จะใช้โปรเจคที่ท่านอาจารย์เตรียมไว้ให้ โดยจะทำการ clone โปรเจคมาที่โฟลเดอร์ที่เราทำ workshop

และ cd เข้าโปรเจค สั่งติดตั้ง package ด้วย npm install และเปิด vscode

git clone https://github.com/saknarak/demo-api.git demo-api-original
cd demo-api-original
npm install
code .

เมื่อเปิด vscode แล้วจะได้ตามภาพ

config.js : เป็นไฟล์ที่เอาไว้ตั้งค่าต่อกับ Database

ถัดมาที่ไฟล์ index.js : เป็นไฟล์เริ่มต้น server api ที่มี middleware เตรียมมาให้

ในบรรทัดที่ 58 จะเป็นการเรียกไฟล์ Route API จาก api/index.js ซึ่งไฟล์นี้ก็จะไปดึง Route จริงๆมาอีกทีนึง

api/index.js
login.js

ที่ไฟล์ index.js ในบรรทัดที่ 48–51

app.use((req, res, next) => {
req.db = require('./lib/db')
next()
})

มี middleware ที่ทำการ set ค่าให้ req.db โดยการทำงานในไฟล์ /lib/db.js

คือการเรียกใช้ library knex.js ที่เอาไว้ Query Database โดยเขียนคำสั่ง SQL ทำให้สามารถเรียกใช้งานค่า req.db ได้จาก /api/student.js ได้เลย

การใช้งาน Knex.js เทียบกับ My SQL Query

MY SQL and Knex.js
--------------------------------------------------------------------
1. SELECT * FROM student;
db('student')
--------------------------------------------------------------------
2. SELECT id,name FROM student;
db('student').select(['id','name'])
--------------------------------------------------------------------
3. SELECT id, name fullname FROM student;
db('student').select(['id', 'name as fullname'])
--------------------------------------------------------------------
4. SELECT * FROM student WHRE room = '1/1';
db('student').where('room','=','1/1')
db('student').where({'room':'1/1'})
--------------------------------------------------------------------
5. SELECT * FROM student WHRE room = '1/1' AND gender = 'M';
db('student')
.where('room','=','1/1')
.where('gender','=','M')
db('student').where({'room':'1/1', gender: 'M'})- ใช้ได้เฉพาะเงื่อนไขเท่ากับ
--------------------------------------------------------------------
6. SELECT * FROM student WHRE room <> '1/1' AND gender = 'M';
db('student')
.where({'gender':'M'})
.where('room','<>','1/1')
--------------------------------------------------------------------
7. SELECT * FROM student ORDER BY code;
db('student').orderBy('code','asc')
--------------------------------------------------------------------
8. SELECT * FROM student ORDER BY name, lname;
db('student').orderBy('name').orderBy('lname')
--------------------------------------------------------------------
9. SELECT code, CONCAT(fname,' ',lname) as fullname FROM student;
db('student').select([
'code',
db.raw('CONCAT(fname,' ',lname) as fullname')
]) -- การใช้ .raw() กรณีที่ใช้กับ function ของ SQL
--------------------------------------------------------------------
10. SELECT code, name FROM student WHERE name like 'a%';
db('student').whereLike('name', 'a%')
.select(['code', 'name'])
--------------------------------------------------------------------
11. SELECT code, name FROM student
WHERE substring(code, 3, 2) = '01'
db('student')
.where(db.raw('substring(code, 3, 2)'),'=','01'))
.select(['code','name'])
db('student')
.where(db.raw('substring(code, 3, 2) = \'01\''))
.select(['code','name'])
--------------------------------------------------------------------
12. SELECT s.code, s.name, d.name as dep_name
FROM student s JOIN department d
ON s.dep_code = d.code
WHERE d.code = '01'
ORDER BY s.code
db.('student as s')
.join('department as d','s.dep_code','d.code')
.where('d.code','=',req.query.code)...
db.('student as s')
.join('department as d','s.dep_code','d.code')
.where('d.code','=','01')...
db.('student as s')
.join('department as d','s.dep_code','d.code')
.where({'d.code':'01'})
.orderBy('s.code')
.select(['s.code','s.name','d.name as dep_name'])
--------------------------------------------------------------------
13. SELECT s.code, s.name, d.name as dep_name
FROM student s JOIN department d
ON s.dep_code = d.code AND s.id <> d.id
WHERE d.code = '01'
ORDER BY s.code
db.('student as s')
.join('department as d',knex.raw('ON s.dep_code = d.code AND s.id <> d.id'))
.where({'d.code':'01'})
.orderBy('s.code')
.select(['s.code','s.name','d.name as dep_name'])
db.('student as s')
.join('department as d', function(){
this.on('s.dep_code','=','d.code')
this.on('s.id','<>','d.id')
})
.where({'d.code':'01'})
.orderBy('s.code')
.select(['s.code','s.name','d.name as dep_name'])
db.('student as s')
.join('department as d', function(){
this.on('s.dep_code','=','d.code')
this.on('s.id','<>','d.id')
if(true){
this.on('s.id','<>','d.id')
}
this.on(db.raw(''))
})
.where({'d.code':'01'})
.orderBy('s.code')
.select(['s.code','s.name','d.name as dep_name'])
--------------------------------------------------------------------
13. SELECT * FROM student WHERE birth >= '2000-01-01'
AND room = '1/1'
-- ถ้ามี birth ส่งมาให้ where birth
-- ถ้ามี room ส่งมาให้ where room
let sql = db('student')
if(req.query.birth){
sql.where('birth','=',req.query.birth)
}
if(req.query.room){
sql.where('birth','=',req.query.room)
}
...............................................................
db('student').where(function(){
if(req.query.birth){
this.where('birth','=',req.query.birth)
}
if(req.query.room){
this.where('room','=',req.query.room)
}
})

การสร้าง Database

ในที่นี้ผมจะใช้ MySQL : MariaDB ของ Xampp โปรแกรมจำลอง Web Server ประเภทหนึ่งจะไม่ขอกล่าวถึงการติดตั้งเนื่องมีตัวอย่างตาม Youtube

ส่วนที่ทำไมต้องใช้ xampp เนื่องจากไม่อยากลง mysql ตัวเต็ม

ไปทำการ start server : apache และ phpmyadmin ให้เรียบร้อย

จากภาพผมทำการเปลี่ยน port apeche เป็น 8099 เนื่องจาก port 80 ชนกับบางโปรแกรมในเครื่อง การเปลี่ยน port สามารถเปลี่ยนได้ที่ config > Apache (httpd.conf) แล้วค้นหา เลข 80 และเปลี่ยนเป็นเลขอะไรก็ได้ตามสะดวก

Listen 8099
ServerName localhost:8099

จะสามารถเข้า phpmyadmin ได้ที่ http://localhost:8099/phpmyadmin/

ส่วนการสร้าง database ใหม่ ผมจะใช้ collection รองรับทุกภาษา utf8mb4_unicode_ci

จากนั้นจะทำการสร้าง Table student จะสร้าง column อะไรก็ได้ตามสะดวก ส่วนโค๊ด SQL สำหรับสร้าง Table student และใส่ข้อมูล ตามตัวอย่างด้านล่าง

จากนั้นผมทำการสร้าง user admin ด้วยคำสั่ง

CREATE USER demoadmin@'localhost' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON demoapp.* TO demoadmin@'localhost WITH GRANT OPTION;
CREATE USER demoadmin@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON demoapp.* to demoadmin@'%' WITH GRANT OPTION

จากนั้นกลับไป ที่ VSCode ที่ file config.js แก้ไขในส่วน port และ db ตามที่สร้างไว้ด้านบน โดยจะแก้ไข port,user,password,database

API ดึงข้อมูลจากฐานข้อมูล (Read)

ไปที่ไฟล์ api/student.js และทำการเพิ่มโค๊ดในส่วนที่ไฮไลท์ ซึ่งเป็นฟังก์ชันในการดึงข้อมูลจาก Table student ซึ่งจะเหมือนกับคำสั่ง SQL

SELECT * FROM student
// http://localhost:8888/api/student // path การเข้าถึง api
router.get('/', async (req, res) => { // ใช้ async function
try {
let db = req.db
let rows = await db('student') // ใช้ await เพื่อรอผลรับ
res.send({
ok: true, // ส่ง status
student: rows, // ส่งค่ากลับ
})
} catch (e) {
res.send({ ok: false, error: e.message })
}
})

จากนั้นใช้คำสั่งเพื่อ start server

nodemon index

จากนั้นไปที่ Browser และเข้าไปที่ http://localhost:8888/api/student

ถ้า api สามารถต่อ database ได้ถูกต้องจะแสดงข้อมูล student ตามภาพ หลังจากนั้นกลับไปที่ phpmyadmin > Structure > Add colum ทำการเพิ่ม column คลิก Go

จากนั้นจะทำการเพิ่ม column ชื่อ class สำหรับนักเรียน type int กด Save

จะแสดงข้อความการเพิ่ม column สำเร็จ

จากนั้นจะไปที่ Browse กด check all และ Edit เพื่อทำการแก้ไข class

หลังจากแก้ไขเสร็จ ระบุหมายเลข class

เมื่อแก้ไข database เสร็จแล้วไปที่ Browser ที่เปิด API ไว้แล้วกดรีเฟรช ดูผลจะได้ข้อมูลของ class เพิ่มขึ้นมาด้วย

ต่อมาให้กลับไปที่ VSCode file : api/student.js โดยเราจะทำให้ API Student สามารถระบุเงื่อนไขเลือกตามค่าที่ส่งไป เช่น ส่ง class=1 ที่ QueryString

Example : http://localhost:8888/api/student?class=1

let rows
if(req.query.class){
rows = await db('student').where('class','=',req.query.class)
} else {
rows = await db('student')
}

จากโค๊ดจะทำการเช็ค req.query.class ว่ามีค่าส่งมาหรือไม่ ถ้ามีให้ where ด้วย class ถ้าไม่มีให้ select มาทั้งหมด

หลังจากนั้นกด ctrl+s เซฟและไปที่ Browser url

Example : http://localhost:8888/api/student?class=2

จากภาพทดสอบ class ให้เท่ากับ 2 ก็จะได้ผลลัพธ์ตามภาพ

API แก้ไขข้อมูล (Update)

จากไฟล์ /api/student.js บรรทัดที่ 49 จะเป็นส่วนที่เรียกใช้ post ข้างใน function ผมจะลบออกไป

ส่วนการรับค่าจาก Post นั้น express จะใช้ library ที่ชื่อว่า bodyParser มาช่วยในการทำงานซึ่งในโค๊ดตัวอย่างได้ทำการเรียกใช้เรียบร้อยแล้ว

โดยการใช้งานรับค่าคือ req.body ซึ่งจะเป็น object

ถัดมากลับไปที่ไฟล์ /api/student.js ทำการเพิ่มโค๊ดในส่วน update ค่า student

// /api/student/save
router.post('/save', async (req, res) => {
let db = req.db
// UPDATE student SET fname=?, lname=? WHERE id = 1
await db('student').where({id: req.body.id}).update({
fname: req.body.fname,
lname: req.body.lname
})
res.send({ok: true})
})

จากโค๊ดจะทำการ update fname,lname ด้วยค่าที่ได้รับมาจาก post และให้ where หา id ด้วย req.body.id

การส่งค่าไปทำการ update จะใช้เครื่องมือที่ชื่อว่า Postman ที่ติดตั้งไปแล้วในตอนแรกๆ

เปิดขึ้นมาเลยจากภาพจะทดสอบ GET ไปที่ http://localhost:8888/api/student/ และ กดที่ปุ่ม Send ก็จะได้ผลลัพธ์มาเป็นรายชื่อ student

หลังจากนั้นจะทำการส่งค่าด้วย Post ตาม Step

  1. เลือก method POST
  2. ใส่ url : http://localhost:8888/api/student/save
  3. เลือก Body
  4. เลือก raw
  5. เลือก JSON(application/json)

จากนั้นใส่ JSON data ลงไป

{
"id": 1,
"fname": "NewNameNaja",
"lname": "NewLastNameNaja"
}

หลังจาก กด Send ตู้ม จะได้ { ok: true }

ลองใช้ Postman GET ค่าดูอีกครั้งจะเห็นว่า fname และ lname ถูกเปลี่ยนไปแล้ว

API ลบข้อมูล (Delete)

จากไฟล์ /api/student.js เช่นเดิมการทำ router สำหรับลบข้อมูลจากภาพมี 2 ตัวอย่าง

โค๊ดตัวอย่างที่ 1

// /api/student/1
router.delete('/:id', function (req, res) {
req.db('student').where({id: req.params.id}).delete().then(() =>{
res.send({status: true})
}).catch(e => res.send({status: false, error: e.message}))
})

โค๊ดใน function จะทำการค้นหา student ด้วย id: req.params.id แล้วทำการลบถ้าลบสำเร็จให้ส่ง stutus:true กลับไป ซึ่ง req.params.id คือค่าที่มาจาก url นั่นเอง

เปิด Postman มาอีกครั้งทำตาม Step

  1. เลือก Method Delete
  2. ใส่ url : http://localhost:8888/api/student/1 << 1 คือ id ที่ต้องการลบ
  3. กดปุ่ม Send
  4. ผลลัพธ์หากลบสำเร็จ

หลังจากนั้นลอง Get ค่าดูอีกครั้งหากทำถูกต้อง student ที่มี id = 1 จะถูกลบไป

โค๊ดตัวอย่างที่ 2

// /api/student/delete
router.post('/delete', async (req, res ) => {
let db = req.db
await db('student').where({id: req.body.id }).delete().then(() =>{
res.send({status: true})
}).catch(e => res.send({status: false, error: e.message}))
})

โค๊ดนี้จะคล้ายกับการ update ข้อมูลโดยใช้ post ในการส่ง id ไปค้นหาและลบข้อมูล

เปิด Postman ขึ้นมาทำตาม Step เช่นเดิม

  1. เลือก Method Post
  2. ใส่ url : http://localhost:8888/api/student/delete
  3. เลือก Body > raw > JSON(application/json)
  4. ใส่ค่า JSON id ที่ต้องการลบ
  5. กดปุ่ม Send
  6. ผลลัพธ์หากลบสำเร็จ

หลังจากนั้นลอง Get ค่าดูอีกครั้งหากทำถูกต้อง student ที่มี id = 2 จะถูกลบไปเรียบร้อย

API สร้างข้อมูลใหม่ (Create)

จากไฟล์ /api/student.js เช่นเดิมจะเพิ่มในส่วนของการ สร้างข้อมูลใหม่หรือ Insert

โค๊ดตัวอย่าง

// /api/student/new
router.post('/new', async (req, res) => {
let db = req.db
let ids = await db('student').insert({
code: req.body.code,
fname: req.body.fname,
lname: req.body.lname,
fType: req.body.ftype,
birth: req.body.birth,
class: req.body.class
})
res.send({
ok: true,
ids: ids
})
})

จากโค๊ดจะทำการ insert ข้อมูลลง Table student ตามคอลัมน์ในฐานข้อมูลโดยรับค่ามาจาก post body

การ insert ข้อมูลโดยใช้ knex.js จะมีการคืนค่ากลับออกมาเป็น id หากมีการตั้ง auto increment ไว้

เปิด Postman ขึ้นมาทำตาม Step

  1. เลือก Method Post
  2. ใส่ url : http://localhost:8888/api/student/new
  3. เลือก Body > raw > JSON(application/json)
  4. ใส่ค่า JSON id ที่ต้องการเพิ่มข้อมูล
  5. กดปุ่ม Send
  6. ผลลัพธ์หากเพิ่มข้อมูลสำเร็จ จะได้ id กลับมาด้วย

ลอง Get ค่าดูอีกครั้งหากทำถูกต้อง จะเห็นข้อมูลที่ทำการเพิ่มไปที่ id = 6

จบ part 5 ครับ

--

--