รีวิว NestJS 7 (มินิ)
Table of contents
Intro
รีวิว NestJS 7 (ฉบับเร่งรีบ) โดยเป็นการเล่าภาพรวมของ Framework ไม่ได้เจาะลึกมากมาเริ่มกันเลยครับ
เกี่ยวกับ NestJS เบื้องต้น
NestJS คือ *Framework ที่มีประสิทธิภาพ เบื้องหลังทำงานด้วย Node.js เป็น server-side ใช้ภาษา JavaScript และรองรับภาษา TypeScript เต็มรูปแบบ (บน github มียอดดาว 26.9k เมื่อ 05/2020) 👍
*Framework คือกรอบหรือข้อตกลงสำหรับการใช้งาน โดยผู้พัฒนา Framework ได้กำหนดกฎเกณฑ์สำหรับการพัฒนาไว้แล้ว ซึ่ง Framework เหมาะสำหรับการพัฒนาระบบเป็นทีม ที่ต้องการความยืดหยุ่น กรอบแบบแผนที่ชัดเจน เพื่อใช้สื่อสารกันในทีมได้ง่าย อีกทั้งยังบำรุงรักษา Code ได้ง่าย
เบื้องหลัง HTTP Server ของ NestJs ใช้ Express (default) และสามารถเปลี่ยนไปใช้ Fastify สำหรับงานที่ต้องการประสิทธิภาพสูง
แนะนำเกี่ยวกับ TypeScript (ขออนุญาตนำเนื้อหาบางส่วนของคุณ NSLog0 มาให้อ่าน) อ่านต่อที่ https://medium.com/p/a83781395dc0
สรุปรีวิว NestJS 7
- สนับสนุนภาษา TypeScript เต็มรูปแบบ (แต่ก็สามารถเขียน Pure JavaScript ได้)
- เป็น Backend Framework เน้นเพื่อใช้สร้าง API เป็นหลัก (สามารถทำเป็น MVC ได้ ใช้ hbs (Handlebars) Template engine)
- เบื้องหลัง HTTP Server ของ NestJS ใช้ Express (default) และสามารถเปลี่ยนไปใช้ Fastify สำหรับงานที่ต้องการประสิทธิภาพสูง
- ทำงานกับฐานข้อมูลได้ทั้ง SQL และ NoSQL โดยสามารถเลือกได้ว่าอยากใช้ Packages อะไรเช่น TypeORM, Sequelize, Mongoose
- ส่วนใหญ่เรียก Model ว่า Entity โดยเฉพาะถ้าใช้ TypeORM ด้วยแล้วนั้น คนที่เพิ่งมาศึกษาใหม่ไม่ต้อง งง 😅
- มีระบบ Sync entity เวลาสร้าง Entity เสร็จ ระบบก็จะสร้างตารางในฐานข้อมูลให้เลย (สะดวกในตอน Develop)
- ทั้ง TypeORM, Sequelize สามารถสร้างระบบ Magration tables ได้ด้วย กรณีต้องการเปลี่ยนแปลงโครงสร้างเฉพาะส่วน
- ไม่มีระบบประกาศไฟล์ Route !! (หากคุ้นเคย Framework อื่น ๆ จะมีการประกาศ Route path ไว้ที่ไฟล์สักที่) NestJS จะใช้วิธีประกาศ Route Path ไว้ที่ Controller เลยครับ โดยใช้ Decorator pattern (อันนี้ก็ง่ายดี บางคนก็ไม่ชอบ 😅)
- มีระเบียบเรียบร้อย เพราะมีระบบ Module โดยสามารถจัดกลุ่มของ Services ง่าย เหมาะอย่างมากสำหรับการแบ่งงาน ให้ทีมให้รับผิดชอบพัฒนา เมื่อพัฒนาเสร็จก็มา Plug-in ต่แเข้า Main Module อีกทั้งยังสามารถทำ Migration แยกแต่ละ Module ได้ด้วย
- มีระบบ CLI สำหรับเป็นเครื่องมือช่วยสำหรับใช้งานต่าง ๆ เช่นสั่ง Generate Module, Controller, Middleware, Pipe เป็นต้น
- มีระบบ Middleware และระบบ Guards เพื่อใช้ออกแบบระบบ Permissions, Roles, ACLs
- มี Interceptors ให้ใช้เพื่อสามารถ Custom อะไรบางอย่างในตอน Request และตอน Response
- ความสามารถสร้าง GraphQL นั้นถูกครอบไว้บน Apollo server อีกที นั้นทำงานได้ดีมากกับ TypeScript โดยการกำหนด GraphQL schema รูปแบบ Class และใช้ Decorators กำหนดโครงสร้างของ Fields ต่าง ๆ ภายใน Class
- มี Module WebSocket ที่สามารถทำงานกับหลายตัว เช่น Socket.io ด้วยการสร้าง Adapter อีกทีนึงสำหรับใช้งาน Library นั้น ๆ
- ความสามารถต่อกับ Service หลายตัวสำหรับการทำ Microservice อีกทั้งยังสามารถใช้ความสามารถของ Exception filters, Pipes, Guards และ Interceptors ร่วมด้วยได้
ระบบ Controller
Ref: https://docs.nestjs.com/controllers
- ยังคงคอนเซ็ปของ Controller ที่จะคล้าย ๆ กับ Framework ส่วนใหญ่อื่น ๆ ไว้ โดยมีหน้าที่รับ Requests และ Responses เนื้อหา
- แต่มีจุดสังเกตของระบบ Routing นั้นจะอยู่ใน Controller เลย โดยใช้ความสามารถของ Decorators โดยกำหนดความสามารถต่าง ๆ เช่น Path, Parameter, Method
- การรับ Request object นั้นก็ได้รับความสามารถมาจาก Express โดยจะใช้ Decorators เช่น @Req(), @Body, @Query, @Param
- รู้สึกถูกใจกับ Sub-Domain Routing เพราะสามารถดึง Parameter ได้แบบ Wildcard Domain เลย
- ระบบ Request Payloads โดยการทำงานร่วมกับ DTO (Data Transfer Object) ซึ่งเป็นคอนเซ็ป การกำหนดรูปแบบหรือโครงสร้างของข้อมูลที่จะส่งเข้ามาใน Request อีกที ด้วยการใช้ความสามาของ Interfaces ของ TypeScript หรือจะทำเป็น Class ก็ได้
ตัวอย่างการใช้งาน Decorators
- การใช้งาน Decorators กับ Method ต่าง ๆ
import { Controller, Get, Post } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Post()
create(): string {
return 'This action adds a new cat';
}
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
- Decorators กับการ Response status code
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
- Decorators กับการ Response Headers
@Post()
@Header('Cache-Control', 'none')
create() {
return 'This action adds a new cat';
}
- Decorators กับการ Response Redirection
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
return { url: 'https://docs.nestjs.com/v5/' };
}
}
สำหรับกับการเขียน Testing บน NestJS
- มี Nest testing ในตัว ทำงานร่วมกับ Jest.js อีกที (Testing Framework ของ Facebook 😎)
- ตอนเขียน Testing สามารถเขียนรวมไว้ที่ Folders งานได้เลย
- ขื่อไฟล์ บ่งบอกถึง Spec งาน เช่น cats.controller.spec.ts (จะไม่ถูก Build ตอนใช้งานจริง)
- มี Unit testing (เป็นการเขียน Testing แบบปกติ)
- และมี End-to-end testing (อารมณ์เหมือนใช้ Postman) เป็น Simulate HTTP requests เหมาะเอาไว้เขียน Testing ในรูปแบบทดสอบ Controller ผ่าน GET, POST
- มี Testing utilities สรุปสั้น ๆ เป็นฟังก์ชั่นช่วยเฉพาะภายใน NestJS เอาไว้ช่วยในการเขียน Testing
คำถามต่อมาควรเขียน Testing ไหม ? เขียนตอนไหน ?
- ควรเขียน เขียนเฉพาะที่เป็นส่วน Service ก็ได้
- ถ้าเขียนมันก็จะมี Spec งานให้ดู คนอื่นมาทำต่อ ก็ทำความเข้าใจง่าย 👍
สรุป
NestJS นั้นเหมาะมากสำหรับผู้ที่ชอบภาษา TypeScript (รองรับ JavaScript ด้วยเช่นกัน) มีความเป็น Enterprise Framework และมีเครื่องมือที่มีคุณสมบัติพร้อมใช้หลายตัว โดยมุ่งเน้นเพื่อให้พัฒนา API เป็นหลัก แต่ก็สามารถใช้ MVC (Model-View-Controller) ได้เช่นกัน
ระบบคอนเซ็ป Modules โดยส่วนตัวเป็นอะไรที่ชอบเป็นพิเศษ เพราะ Framework อื่น ๆ แทบหาคุณสมบัตินี้ไม่ได้ ซึ่งการทำงานจะเป็นลักษณะการจัดกลุ่มของ Services Providers, Controllers นำมาเชื่อมกันเป็น Module จากนั้นก็สามารถนำไปต่อกับ Module หลัก ท ำให้มีประโยชน์มากสำหรับการแยกสัดส่วนการพัฒนาระบบ 👍 แต่เดี๋ยวผมจะเขียนเป็นบทความอธิบายเพิ่มเติมให้อ่านกัน
รองรับระบบฐานข้อมูลหลายตัว สำหรับการใช้งานในส่วน ORM นั้นรองรับทั้ง TypeORM Integration และ Sequelize Integration ซึ่งของ TypeORM ก็สุดยอดอยู่แล้ว ใช้ได้ทั้งแบบ Query Builder และ ORM นอกจากนี้ก็มี GraphQL ที่ใช้ TypeScript classes สร้างเป็น GraphQL schema ก็ดูจะเป็นวิธีที่ช่วยงานดูดีและง่ายขึ้นมาก
มีจุดตินิดนึงในส่วนส่วนระบบ Routing ส่วนตัวไม่ชอบระบบ Routing ที่ผูกไว้กับ Controllers ของ NestJS แบบนั้นเพราะไม่มีความยืดหยุ่นมากพอ อยากทำ Route ต้องสร้าง Controller ด้วยแบบนี้เหรอ 😅 โดยส่วนตัวชอบระบบ Routing ที่แยกออกมาเป็นไฟล์มากกว่าคล้าย ๆ ระบบ Route ของ AdonisJS Framework
// สมมุติต้องการทำแบบนี้ก็ทำได้ง่ายกว่า
// ประกาศหลาย routes ไปที่ controller และ method เดียวกัน
Route.get('users/:id', 'UserController.show')
Route.get('account/:id', 'UserController.show')
ลองเล่นท่ายากแล้วลำบากเหลือเกิน จนถอดใจ ผมลองทำโปรเจคง่าย ๆ เพื่ออยากรู้ว่า NestJS ทำได้ไหม เช่น สร้าง Model แยก Connections ของ Database ต่างชนิดกัน สรุปคือทำได้ แต่ไม่ง่าย และต้องไปกำหนดหลายอย่าง และทุกครั้ง ไม่เหมาะกับคนขี้เกียจ และช่วยให้ทำงานง่ายขึ้น
TypeORM ออกแบบระบบ Relationship ไว้แบบว่าทุก Tables ที่จะทำความสัมพันธ์ต้อง Join กัน เห็นแค่นี้ก็จบแล้วเพราะไม่สามารถเขียนความสัมพันธ์ข้าม Connections ต่างชนิดกันได้ อาจจะต้องใช้ Sequelize แทน
สุดท้ายส่วนตัวมองว่า NestJS ค่อนข้างยากและต้องความเข้าใจคอนเซ็ปของ Framework ในระดับนึงก่อน แนะนำให้ตั้งใจอ่าน Docs สักหน่อย 😅 (กลัวถอดใจก่อน ผมเองก็อ่านนานเลยกว่าจะเข้าใจ) แรก ๆ อาจจะดูแบบ งง ๆ แต่พอเข้าใจหลักการแล้ว และได้ลองเขียน TypeScript แล้วนั้นก็ถือเป็นสุดยอด Framework ที่ดีตัวนึงเลย สมแล้วที่ได้ดาวบน Github 26.9k (2020) ทั้งนี้ NestJS ก็ยังปล่อยตัวอย่าง Code สำหรับตัวอย่างการใช้งานในรูปแบบต่าง ๆ ให้อ้างอิง ก็อยากให้ลองเล่นกันดูครับ https://github.com/nestjs/nest/tree/master/sample
References