สร้าง RESTful API ด้วย Node.js + Express เบื้องต้น

ช่วงนี้ผมได้มีโอกาสสร้าง RESTful API รัว ๆ ด้วย Node.js เนื่องจากเขียนง่าย ด้วย Syntax ภาษา JavaScript เพราะมีพื้นฐานมาบ้าง บวกกับ Framework ที่ชื่อ Express นั้น ก็ยิ่งทำให้การสร้าง RESTful API ทำได้ง่ายและรวดเร็วมากขึ้นไปอีก ก็เลยมาเขียนบทความทิ้งไว้สำหรับผู้เริ่มต้น ได้เป็นแนวทางในการเรียนรู้

ก่อนอื่น ขอพูดถึง Node.js นิดนึง เนื่องจากตอนที่ผมได้ยินชื่อ Node.js แรก ๆ พอรู้มาว่าใช้ Syntax ของภาษา JavaScript แต่ทำงานบน Server เนื่องจากผมเคยได้จับงานเว็บมาบ้างเมื่อนานมาแล้ว ทำให้เกิดความสงสัยว่ามันจะไปรันบน Server ยังไง เพราะความรู้เดิมคือ JavaScript ต้องรันบน Browser!!

พอได้ลองเขียนนิดหน่อย ก็พบว่า นอกจากจะรันบน Server ได้แล้ว ตัวมันเองยังเปิด Port เป็น Web Server ได้ด้วยตัวเอง ไม่ต้องพึ่งพา Web Server เลย Lightweight มาก ๆ

พอเริ่ม ๆ เขียนไปอีกซักหน่อย ก็ได้รู้จัก npm ที่แถมมาตอนติดตั้ง Node.js อยู่แล้ว ซึ่งเป็น Package manager ที่ทรงพลังมาก ๆ อยากได้ Dependency อะไร ก็พิมพ์ Command เอา มันจะไปลาก Dependency ที่มันใช้งานต่อ ๆ กันเป็นทอด ๆ มาให้หมด ชีวิตดี๊ดีย์

พอรู้จัก npm ไม่นาน ก็เริ่มหา Dependency ที่ช่วยสร้าง RESTful API ง่าย ๆ แล้วก็ได้เจอ Framework ของ Node.js ตัวนึง ที่ชื่อว่า Express ซึ่งจากการค้นข้อมูลดูไม่นานก็พบว่า เป็น Framework ยอดนิยม ด้วย GitHub star หลักหมื่นเลยทีเดียว

 

Hello World, Express

ก่อนที่จะใช้ Express นั้น เราจำเป็นต้องสร้าง Node project ก่อน ด้วยคำสั่ง

เมื่อสร้างเรียบร้อยแล้ว จะได้ไฟล์ package.json หน้าตาแบบนี้

หลังจากนั้นก็ติดตั้ง Express ด้วยคำสั่ง (อย่าลืมต่อ Internet)

ก็จะได้ Express มาใช้แล้ว (อยู่ใน Folder node_modules) ซึ่ง package.json ก็จะมี Express เพิ่มเข้ามาในส่วนของ Dependency

แล้วทำการสร้างไฟล์ index.js ไว้ที่ Path เดียวกับ package.json โดย Copy code มาจากหน้า Hello world บนเว็บ Express มาเลย

เซฟให้เรียบร้อย แล้วรันคำสั่ง

ถ้าไม่มีอะไรผิดพลาดตาม Code บรรทัดที่ 8 จะทำการเปิด Web Server ที่ Port 3000 ให้ลองเปิด Browser ไปที่ http://127.0.0.1:3000 ดู ก็จะได้หน้า Hello World! มาแล้ววววว

จาก Code ด้านบน อธิบายคร่าว ๆ ได้ว่า ได้กำหนดให้มี Route / (Parameter ตัวแรก ในบรรทัดที่ 4) ที่ HTTP Method GET (app.get()) โดยหากมีการเรียกมาที่ Route นี้ จะให้ Express ทำการ Callback (Parameter ตัวที่สอง ในบรรทัดที่ 4) มายัง Anonymous function ที่มี 2 Parameter คือ req (Request) และ res (Response) ซึ่งในตัวอย่าง จะทำการ Response ข้อความว่า Hello World! ออกไป

และให้ Express ทำการเปิด Listen (app.listen()) ที่ Port 3000 หากสำเร็จ ให้ Callback กลับมา เพื่อพิมพ์ข้อความออกทาง Console

หากต้องการ Down Web Server ให้กด Ctrl + C

ก่อนจะไปกันต่อ ขอปรับ Syntax ของ Code ด้านบนเป็น JavaScript ES6 ไปใช้ Arrow Functions นิดหน่อย

 

โจทย์ในการทดลองสร้าง RESTful API

สำหรับโจทย์ในการทดลองสร้าง RESTful API ง่าย ๆ เพื่อให้ได้ทดลองใช้งาน HTTP Method GET, POST, PUT, DELETE ได้ลอง Response data ชนิด JSON ได้ลองตอบ HTTP Status Code ต่าง ๆ เช่น 200, 404 หรือการรับข้อมูล JSON ทาง Body ด้วยโจทย์ตามตารางนี้

โดยสมมติ RESTful API นี้ มีหน้าที่เก็บข้อมูล item และจัดการข้อมูลนั่นเอง ซึ่งผมได้ออกแบบไว้เป็น Module ในไฟล์ store.js ที่สอดคล้องกับโจทย์ ดังนี้

แล้วที่ index.js ทำการเรียกใช้งาน store.js ดังนี้

บรรทัดที่ 3 ทำการเรียกใช้ไฟล์ store.js โดยอ้างไว้ที่ตัวแปร store แล้วที่บรรทัดที่ 7 เรียกใช้งาน Method init() ของ store เพื่อให้เตรียมค่าเริ่มต้น

 

HTTP Method GET

เริ่มด้วย Route แรกกันก่อน เมื่อเรียกใช้งานมาที่ http://127.0.0.1:3000/item/ ตามโจทย์คือต้องตอบ HTTP Status 200 และตอบข้อมูลเป็น JSON ออกทาง Body ตาม Code ด้านล่าง (นำไปเขียนต่อจาก Route / หรือจะลบ Route เดิมออกไปก่อนก็ได้)

เนื่องจาก Route นี้ จะส่งข้อมูลทั้งหมดใน Array ที่เก็บอยู่ใน store.js จึงเรียกใช้งาน store.getAllItems() ซึ่งจะคืนค่าเป็น Array ของ Item อยู่แล้ว และนำไปกำหนดให้ JavaScript Object ที่มี key เป็น items แล้วจึงส่งข้อมูลกลับ Client ผ่านทาง res.send()

เมื่อลองรัน แล้วลอง Request ดู ก็จะได้ผลลัพธ์เป็นดังรูป (แนะนำให้ใช้ Postman ซึ่งเป็น Chrome Extension ในการ Request เพราะสามารถเลือก HTTP Method ได้)

Postman request HTTP GET

จากรูปผมใช้ Postman ยิง HTTP GET ไปที่ http://127.0.0.1:3000/item/ สังเกตุว่า จะได้ HTTP Status Code 200 (Express กำหนดให้เป็น 200 เมื่อมีการส่งข้อมูลกลับมา) และข้อมูลใน Body จะเป็น JSON แล้ว

Postman request HTTP GET

ลองสังเกตุที่ Response Header จะพบว่า Express มีการกำหนด Content-Type เป็น application/json ไว้ให้แล้ว (Express ทำการสร้างให้อัตโนมัติเมื่อข้อมูลที่ตอบกลับเป็น JavaScript Object)

เสร็จแล้วครับ Route แรก ^_^

สำหรับ Route ที่ 2 ยังเป็น Method GET อยู่ แต่จะมีการส่ง Parameter index มาด้วย (/item/{index}) เพื่อบอกว่า จะเอา Item จาก Store ที่ Index ไหน ก็จะมีหน้าตาประมาณนี้

สำหรับ Express การกำหนด Parameter แรกให้กับ Method .get() เป็น /item/:index ตรง :index จะเป็น Parameter ที่ส่งมาจากภายนอก และจะเป็นชนิด String เสมอ เราสามารถอ่านค่าออกมาได้จาก Attribute params ของตัวแปร req ตามบรรทัดที่ 4 ด้านบน (req.params.index) แล้วทำการแปลงเป็นตัวเลขด้วย Function Number() และเก็บค่าไว้ในตัวแปร index เพื่อนำไปใช้เป็น Parameter ของ Method .getItem() ของ store ต่อไป แล้วจึงนำผลลัพธ์ที่ได้ มาสร้าง JavaScript Object ({ item }) ก่อนส่งข้อมูลกลับ

ทดสอบได้โดยการยิง HTTP GET ไปที่ http://127.0.0.1:3000/item/0 ดูได้เลยครับ

แต่เนื่องจากผลลัพธ์ที่ Return มาจาก Method .getItem() ของ store มีโอกาสที่จะไม่ได้ข้อมูล (ข้อมูล Return ออกมาเป็น undefined) เนื่องจาก index ที่ส่งเข้ามา มีค่ามากกว่า index สุดท้ายของ item ใน store จึงจำเป็นต้องตรวจสอบผลลัพธ์ก่อน

Code ด้านบน ได้เพิ่มเงื่อนไขการตรวจสอบ item และถ้าเป็น undefined ก็จะ Response HTTP Status Code 404 กลับไปเลย

Route ที่ 2 เสร็จแล้ววววววววววว

 

HTTP Method Post

สำหรับ Code ในส่วนของ Method Post นั้น เนื่องจากจะมีการส่งข้อมูล JSON มาจาก Client ซึ่ง Express นั้น ไม่สามารถตีความ JSON ใน Body ได้ จำเป็นต้องใช้ Middleware เข้ามาช่วย พระเอกของงานนี้ก็คือ body-parser

เพราะฉะนั้น เราจะต้องติดตั้ง body-parser ก่อน ด้วยคำสั่งดังนี้

เมื่อติดตั้งเรียบร้อย ใน package.json ก็จะมี body-parser เพิ่มเข้ามาดังนี้

หลังจากนั้น ให้เรียกใช้งาน json-parser ในไฟล์ index.js

บรรทัดที่ 2 เป็นการนำ Module body-parser มาใช้ โดยอ้างอิงไว้ที่ตัวแปร bodyParser แล้วทำการเรียกใช้งาน Method json() ที่บรรทัดที่ 7 แล้วนำ Output ที่ได้ กำหนดเป็น Middleware ให้กับ Express ด้วย Method use() นั่นเอง

ถึงตรงนี้เราก็สามารถที่จะให้ Express ทำการแกะข้อมูล JSON ทาง Request body และ body-parser จะทำการแปลงให้เป็น JavaScript Object ให้แล้ว ก็ลุย Route สำหรับ HTTP Method Post กันได้เลย

สำหรับ Code ด้านบน เราจะใช้ Method .post() ในการรับ Request เป็น HTTP Method Post ที่ Route /item/ และที่บรรทัดที่ 4 ทำการอ่านข้อมูลออกมาจาก Body ที่ส่งเข้ามา โดยจะอ่านค่า JSON ที่ส่งเข้ามาด้วยเฉพาะ Key ที่ชื่อ item (req.body.item) แล้วกำหนดค่าให้ store ผ่านทาง Method .addItem() ต่อไป เสร็จแล้วทำการ Response HTTP Status Code 201 กลับไปยัง Client และจบด้วยการเรียก Method .end() เพราะไม่มีข้อมูลใด ๆ ที่จะส่งกลับ Client

ลอง Request ด้วย Postman ดู โดยกำหนด HTTP Method Post และกำหนดให้ Body ส่งข้อมูลเป็น JSON ดังรูป

Postman request HTTP POST

เนื่องจากมีการส่งข้อมูลมาทาง Body จาก Client ซึ่งมีโอกาสที่จะส่งข้อมูลมาไม่ถูกต้อง จึงจำเป็นต้องมีการตรวจสอบข้อมูลก่อน หากไม่ถูกต้อง ก็ควรจะ Reject ออกไป ด้วย HTTP Status Code 400 ดังนี้

เรียบร้อยแล้วครับ สำหรับ Route ที่เป็น Method Post

 

HTTP Method Put

จากโจทย์นั้น กำหนดให้ HTTP Method Put ใช้สำหรับแก้ไขข้อมูลใน Store โดยการบอก Index ของ Item ที่ต้องการแก้ไขมาทาง Parameter และข้อมูลที่จะแก้ไข ส่งมาทาง Body ซึ่งวิธีการเขียนคำสั่ง ก็จะเหมือนนำ Code จาก Route GET /item/{index} และ POST /item/ มาผสมกันนั่นเอง ก็จะได้ Code ออกมาหน้าตาแบบนี้

เนื่องจากการแก้ไขข้อมูล ต้องบอกว่าจะแก้ไขที่ Index ไหน (:index) ก็นำค่า Index มาตรวจสอบได้จาก req.params.index และข้อมูล JSON ที่ส่งมาทาง Body ก็จะมีหน้าตาเหมือนกับตอนเพิ่มข้อมูล ก็สามารถนำข้อมูลออกมาจาก req.body ได้เช่นกัน เพราะว่าเรามีการนำ body-parser มาใช้ Parse ข้อมูล JSON อยู่ก่อนแล้ว

และจากโจทย์ จะต้องส่งข้อมูลก่อนแก้ไขคืนกลับไปด้วย ตรงนี้ Method .updateItem() ของ store ได้ Return ออกมาให้อยู่แล้ว ก็ส่งคืนกลับ Client ได้เลย

 

HTTP Method Delete

ส่วนการลบข้อมูลใน Store เราจะใช้ HTTP Method Delete ซึ่งก็จะต้องบอก Index ของ ​Item ที่ต้องการลบมาทาง Parameter ซึ่งก็จะเหมือนกับ Route GET /item/{index} เลย ดังนี้

Method .removeItem() ของ store มีการ Return ข้อมูลที่ถูกลบออกมาให้อยู่แล้ว เราก็ส่งกลับให้ Client ได้เช่นกัน

 

สำหรับทั้ง 5 Route ตามโจทย์ที่ตั้งไว้ ก็ Implement ด้วย Express เรียบร้อยแล้ว มาดู Code เต็ม ๆ สำหรับไฟล์ index.js กันอีกครั้ง

และผมได้นำ Code ขึ้น GitHub ไว้แล้ว

 

Bonus

ถ้าใครได้ส่อง GitHub จะเห็นว่ามีไฟล์ Dockerfile อยู่ด้วย หน้าตาแบบนี้

ก็คือการสร้าง Docker image สำหรับ App ที่เป็น Node.js พร้อมที่จะไป Deploy ลง Production นั่นเอง (ไว้เขียนเป็นอีกบทความสำหรับการนำ Docker มาใช้พัฒนา Node.js App ยาวไปจนถึงการ Build จนได้ Dockerfile ด้านบนละกันนะครับ)

 

สรุป

Express นั้น เป็น Framework ของ Node.js ที่ช่วยให้เราเขียน RESTful API ได้ง่าย ๆ ใช้เวลาไม่นาน สังเกตุได้จากที่ Code ในแต่ละ Route นั้น มีเพียงไม่กี่บรรทัด แต่ก็ยังต้องทำความเข้าใจเรื่องการ Response ข้อมูลกับ HTTP Status Code เล็กน้อย รวมไปถึงเรื่องของ Middleware ด้วย

ซึ่งในการนำไปใช้กับงานจริง ๆ Code ใน Route ต่าง ๆ ก็จะประมาณนี้ล่ะ แต่เราจะเอา Business logic ต่าง ๆ ไปไว้ที่ไฟล์อื่น (ในตัวอย่างถึงทำ store.js แยกออกมา) อาจแบ่งเป็นเรื่อง ๆ หลาย ๆ ไฟล์ เพื่อให้ดูแลง่าย รวมถึงการเขียน Unit Test มาคุม เพื่อเพิ่มคุณภาพและลดเวลาการทำงาน

สำหรับการนำไป Deploy นั้น เนื่องจาก Node.js ทำงานได้เร็วมากอยู่แล้ว แต่ก็ยังทำงานอยู่บน Single Thread การรีดประสิทธิภาพออกมา จำเป็นต้องมีตัวมาจัดการ เช่น PM2 หรือ Docker เป็นต้น

 

จบแล้วครับ สำหรับบทความแนะนำ Express ในตอนหน้าที่เตรียม ๆ ไว้ จะเป็น Framework อีกตัวนึง ที่ชื่อว่า Hapi จะมาทำโจทย์เดียวกันนี้เลย

ถ้าใครส่อง GitHub ก็คงเห็นก่อนแล้วละ… ^_^

Leave a Reply

Your email address will not be published. Required fields are marked *