มาลอง CRUD 101 ด้วย NestJS + Prisma กันเถอะ

Thirawat Prasert
Artisan Digital
Published in
6 min readAug 11, 2020

วันนี้เราจะมาลองทำ workshop CRUD เบื้องต้น โดยใช้ NestJS กับ Prisma กันดูนะครับ ถ้าพร้อมแล้วเรามาลองเขียนกันเล้ยยยย

มาทำความรู้จักกันคร่าวๆ ว่ามันคืออะไร ??

NestJS คืออะไรกันนะ ????

NestJS คือ framework สำหรับสร้าง Application ฝั่ง server-side ที่ใช้ Node.js ทำให้ application มี efficient และ scalable มากขึ้น โดยภาษาที่ใช้เขียน NestJS นั้นจะใช้ TypeScript ในการเขียน (หรือจะใช้ JavaScript ก็ได้นะ) และ NestJS ยังมาด้วย concept ของ OOP (Object Oriented Programming), FP (Functional Programming) และ FRP (Functional Reactive Programming) ทำให้เราสามารถ`วางโครงสร้างของ application ได้อย่างเป็น ระบบ นั่นเองงง

ถ้าใครอยากศึกษาเพิ่มเติมสามารถ click ตรงนี้ได้เลยนะค้าบบบ

แล้ว Prisma ล่ะ ????

Prisma คือ open-source database toolkit ที่เป็น Modern Database Access for TypeScript & Node.js ช่วยให้เราเขียน query ข้อมูลจาก database ได้ง่ายขึ้น โดย Prisma นั้นไม่ได้เป็น ORM แต่ว่าาา มันก็จะมี Syntax เป็นของตัวเอง เพื่อทำการ query ข้อมูล เป็นของมันเอง

ถ้าใครอยากศึกษาเพิ่มเติมเกี่ยวกับ Prisma สามารถ click ตรงนี้ได้เลยนะค้าบบบ

อะไรกันครับเนี่ยยยยย

อ่านแล้วดู งงๆ งั้นมาทำกันเลยดีกว่า

สำหรับโปรเจคที่เรากำลังจะสร้างเป็น โปรเจค CRUD เบื้องต้น โดยเราจะใช้ yarn, TypeScript และ MySQL สำหรับโปรเจคนี้กันนะครับ

  • ขั้นตอนแรก เราก็ต้องลงตัว CLI ของ NestJS กันก่อนโดยเปิด Terminal ขึ้นมาแล้วพิมพ์คำสั่งนี้ลงไป
yarn global add @nestjs/cli
  • ต่อไป เราจะมา Create โปรเจคกัน
nest new rov-heroes
  • มันจะให้เลือก Package manager โดยเราจะเลือก yarn กันนะครับ
เลือก Package manager
  • จากนั้นเราก็ทำการเปิด โปรเจค ขึ้นมา หน้าตาโครงสร้างของโปรเจคจะเป็นแบบนี้ครับ
โครงสร้างของโปรเจค

โดยองค์ประกอบหลักๆของ โปรเจคก็จะมี
Controller: คือ ตัวรับ request และ ส่งออกเป็น response ข้อมูล ให้ไปยังฝั่ง Client ซึ่งใน ตัวcontroller ก็จะมีการประกาศ Decorator ต่างๆ เช่น @Get(), @Post(), @Patch(), และ @Delete(), ซึ่ง decorator เนี่ยเราจะเอาไว้กำหนด route ของ API ว่าทำอะไรบ้าง ใช้ที่ไหน ซึ่ง แต่ละ decorator ก็จะสามารถกำหนด route ย่อยๆ ไปได้อีก
Service: เปรียบเทียบง่ายๆ ตัวนี้ก็คือ class นั่นแหละ ที่เอาไว้เขียน logic ซึ่งมันจะ call ผ่าน ตัว controller แต่ว่ามันเป็น class ที่ประกาศเป็น Injectable ซึ่งเป็นการบอกว่าสามารถเอาไปใช้กับใครได้บ้าง
Module: คือ ตัวควบคุมส่วนประกอบต่างๆ เช่น controller และ service โดยเราสามารถรวม Module หลายๆ ตัวได้
Main: ก็คือ file เริ่มต้นของโปรเจค

ขอขอบคุณข้อมูลจาก https://bit.ly/3fIGfYw

  • หลังจากนั้นเราก็มาเริ่มทำการ install prisma
yarn add @prisma/client @prisma/cli -D
  • เมื่อลงเสร็จแล้วก็ทำการ init prisma
yarn prisma init

เราก็จะได้ folder prisma มา ซึ่งก็จะประกอบไปด้วย env file และ schema.prisma จากนั้นเราก็ทำการย้าย folder ไปที่ src หน้าตาก็จะออกมาแบบนี้

ทีนี้ เราก็มา set .env และ schema

Default database url ใน .env ที่ได้มาจะเป็นแบบนี้

Default .env

ดูแล้วก็ งงๆ แล้วเราจะเปลี่ยนให้ตรงกับ database ของเรายังไงล่ะ ??
อธิบายง่ายๆก็คือ database ที่ใช้ username และ password ตามด้วย port ละสุดท้ายชื่อ shecma ที่เราสร้างไว้

DATABASE_URL="database://username:password@localhost:port/shecma?schema=public"
  • มา set database url สำหรับโปรเจคนี้
DATABASE_URL=”mysql://username:password@localhost:port/hello-rov?schema=public”
  • ต่อมาเราก็ไปเปลี่ยน provider ใน shecma.prisma ให้เป็นตามนี้ได้เลย
datasource db {provider = “mysql”url = env(“DATABASE_URL”)}
  • ต่อไปเรามาสร้างตัว Model กัน โดยใส่โค้ดด้านล่างนี้ไปใน ไฟล์ schema.prisma
model Hero {id Int @default(autoincrement()) @idname Stringrole Stringposition Stringlevel Int}
  • เมื่อเราทำการสร้าง model กันแล้วต่อไปก็จะถึงขั้นตอนการสร้าง Migration
yarn prisma migrate save --schema src/prisma/schema.prisma --experimental
  • เมื่อเสร็จแล้วเราก็ Execute migration
yarn prisma migrate up --schema src/prisma/schema.prisma --experimental
  • แล้วก็ generate prisma กัน
yarn prisma generate --schema src/prisma/schema.prisma
  • แล้วเราก็จะสร้างตัว prisma module และ service โดยใช้คำสั่ง
nest g module prisma && nest g service prisma

หน้าตาของ folder prisma ก็จะเป็นแบบนี้

  • เข้าไปที่ไฟล์ prisma.service.ts เพื่อทำการ extends PrismaClient (วางโค้ดนี้ทับไปเลยค้าบบบบ)
import { Injectable } from ‘@nestjs/common’;import { PrismaClient } from ‘@prisma/client’;@Injectable()export class PrismaService extends PrismaClient {}
  • จากนั้นเราก็มา export PrismaService โดยเข้าไปที่ไฟล์ prisma.module.ts
import { Module } from ‘@nestjs/common’;import { PrismaService } from ‘./prisma.service’;@Module({providers: [PrismaService],exports: [PrismaService]})export class PrismaModule {}

สร้าง Module

หลังจากที่เรา Setup prisma กันแล้ว เราก็จะมาเริ่มทำ module กันนะครับ ซึ่งส่วนนี้เราจะทำการสร้างไฟล์ module, controller, และ dto

  • สร้าง module และ controller file
nest g module heroes && nest g controller heroes

หลังจากที่เราลง เสร็จแล้วจะได้ folder ที่ชื่อว่า heroes ซึ่งข้างในจะประกอบไปด้วย module และ controller

เมื่อติดตั้งเสร็จแล้วเราก็จะ import PrismaModule ใน heroes.module.ts

import { Module } from ‘@nestjs/common’;import { HeroesController } from ‘./heroes.controller’;import { PrismaModule } from ‘../prisma/prisma.module’;@Module({controllers: [HeroesController],imports: [PrismaModule]})export class HeroesModule {}
  • หลังจากนั้นให้ทำการ สร้างfolder dto ที่มีและตั้งชื่อไฟล์ว่า heroes.dto.ts หน้าตาที่ได้ก็จะออกมาเป็นแบบนี้ครับ
  • ในไฟล์ dto เราจะสร้าง class ที่ชื่อว่า HeroDto
export class HeroDto {id: number;name: string;role: string;position: string;level: number;}

สงสัยกันมั้ยว่าทำเราไม่มีไฟล์ service ล่ะ แล้วเราจะเขียน logic ตรงไหน
>>>> ความเจ๋งของ prisma มันอยู่ตรงนี้แหละครับ ที่บอกไว้ตอนต้นคือ prisma นั้นมันมี syntax เป็นของตอนเอง เราก็จะใช้ เจ้า prisma นี่แหละเอาไว้เขียน service ทำยังไงเราไปดูกันเลย

มา run project กัน

yarn start:dev

ถ้าขึ้นสีเขียวแสดงว่าาาา มัน run ได้น่ะสิ

แต่ๆๆๆๆ มันยังไม่จบน่ะสิ ต้องไปเช็ค database ด้วย มันก็จะได้แบบนี้

ยังไม่พอก็ต้องเช็ค table Hero ด้วย ว่าตรงกับ model ที่สร้างขึ้นมาในไฟล์ schema.prisma หรือเปล่า

ก็จะได้ ข้อมูล ออกมาเป็นไปตามรูปด้านซ้าย บอกเลยว่าเป๊ะะะะะ
(ถ้าคิดว่าไม่เป๊ะก็เลื่อนขึ้นไปดู model ข้างบนได้เลยนะ อิอิ)

🎊🎊🎊ถ้าเป็นไปตามทั้งหมดนี้ ก็ขอแสดงความยินดีด้วยค้าบบบบ🎊🎊🎊

เริ่มทำ CRUD

เมื่อทำการ set project กันหมดแล้วเราก็จะมาเริ่มทำการเขียน CRUD กันนะครับ
ให้ไปที่ไฟล์ heroes.controller.ts นะครับ

  • สร้าง constructor
import { Controller } from ‘@nestjs/common’;import { PrismaService } from ‘../prisma/prisma.service’;@Controller(‘heroes’)export class HeroesController {constructor(private readonly service: PrismaService) {}}

Create
เราจะมาทำการ create ตัว hero ของเรากันนะครับโดยเราจะประกาศ Decorator @Post()ข้างบน fucntion เพื่อนกำหนด route ของ API ที่ใช้สำหรับ create นะครับ โดยเราก็จะรับค่า ผ่าน body นะครับเพียงค่าทำการประกาศ @Body()

Read
ในการ read เราจะมี 2 functions ได้ก็คือ findAll และ findById นั่นเองครับ

  • findAll
    เราก็จำทำการประกาศ Decorator ที่ชื่อว่า @Get()
  • findById
    เราจะประกาศ Decorator @Get(‘/:id’) ซึ่งแต่ละ decorator เนี่ย เราสามารถกำหนด route ย่อยๆไปได้อีก หน้าตาตอนนำไปใช้ก็จะเป็นแบบนี้ครับ localhost:3000/heroes/{{id}} โดยการ findById เราจะรับ id จาก param นะครับ เพียงแค่เราประกาศแบบนี้

Update
หลังจากที่ได้ทำการ เขียน create และ read ไปแล้วต่อมาเราก็จะทำการ เขียน update กัน โดยให้เราประกาศ Decorator @Patch(‘/updateLevel/:id’) หน้าตาตอนที่เรานำไปใช้ก็จะออกมาเป็นแบบนี้ localhost:3000/heroes/updateLevel/{{id}}
ใน function นี้เราจะมา update level ของ hero กันโดยที่จะรับ id จาก param และ level จาก body

Delete
และ function สุดท้ายของเราก็คือ delete นั่นเองครับเราก็จะ ประกาศ Decorator @Delete(‘/deleteHero/:id’) หน้าตาตอนเอาไปใช้ก็จะเป็นแบบนี้ครับ localhost:3000/heroes/deleteHero/{{id}}

จะเห็นได้ว่า ทุก function จะไปเรียกใช้ service จาก prisma ตั้งแต่ ซึ่งเราไม่จำเป็นต้องมานั่งเขียนเองให้ปวดหัว จึงให้เจ้าตัว prisma ไปทำให้ซะเลยเราแค่บอกมันว่าให้มันทำอะไรก็พอ และ เจ้า prisma ก็ไม่ได้มีคำสั่งแค่นี้นะครับ เราสามารถไปศึกษาเพิ่มเติมโดย click ตรงนี้ได้เลย

และนี่คือ Code สำหรับ ไฟล์ heroes.controller.ts นะครับ

มา Test กันว่าที่เขียนมามันใช้ได้จริงหรือเปล่าาาาา

หลังจากที่เราเขียนฟังก์ชั่นไว้หมดแล้ว มันก็ถึงเวลาแล้วล่ะ ที่เราจะมาลงมือ test ว่าหน้าตาที่เราเขียนมันจะออกมาเป็นยังไง

  • ให้เราทำการ run project
yarn start:dev
  • สร้าง Collection และ add request ให้ตรงตามรูปเลยครับ
  • findAll ใส่ url นี้ไปเลยครับ localhost:3000/heroes result ที่ออกมาก็จะเป็นแบบนี้

จะสังเกตุได้ว่า ตรงกรอบด้านล่าง ทำไมมันได้ [] ล่ะ นั่นถูกต้องละครับ เพราะเรายังไม่มี Data ไงละ เราลองไปเช็คใน Database กัน

  • Create ต่อไปเราก็มาทำการ create hero ของเรากันเถอะ โดย copy json ด้านล่างนี้ไปวางใน body
{“name”: “Murad”,“role”: “Assassin”,“position”: “Jungle”,“level”: 1}

ใส่ให้ตรงกับรูปเลยนะครับ เมื่อใส่แล้วก็ลองกด send ดู มันก็จะ return ค่าออกมาในกรอบ ด้านล่าง (อย่าลืมเปลี่ยนให้เป็น Post ล่ะครับ) เสร็จแล้วก็มาเช็คดูใน Database

นี่ไง data เข้ามาแล้ววววววว ทีนี้เราก็มาาร้าง hero ตามใจชอบเลยนะครับ

  • เมื่อทำการสร้าง hero ให้ครบทีมแล้วเราก็มาลอง findAll กันอีกรอบ

แสดงว่า ตอนนี้เราสามารถ ใช้ function create และ FindAll ได้แล้ว

  • ถ้าเราอยากดูแค่ตัวเดียวล่ะทำยังไง??
    เราก็ใช้ request ที่ชื่อว่า findById แล้วเราก็ใส่ url นี้ลงไป ตามด้วย id ของ hero ที่เราอยากจะดู localhost:3000/heroes/{{id}}
  • ต่อไปเราก็จะมาลอง update level ของ hero กัน โดยวาง url นี้ลงไปใน request updatelocalhost:3000/heroes/updateLevel/{{id}} แล้วก็ใส่ id ของ hero ที่ต้องการเปลี่ยน level แล้ว ใส่ level ใหม่ใน body

ขั้นสุดท้ายเราก็มาทำการ Delete hero ออกไป โดยนำ url นี้ไปวางใน request delete localhost:3000/heroes/deleteHero/{{id}}

จะเห็นได้ว่า id ที่ 7 นั่นคือ Murad ตอนนี้ใน database ของเรา Hero Murad ก็จะหายไปจาก database แล้วครับ

สรุป

สำหรับ workshop นี้เป็น เพียงการทำ CRUD เบื้องต้นด้วย NestJS และ Prisma จะเห็นได้ว่า เราไม่จำเป็นต้องเขียน ตัว service เองแต่เราสามารถไปเรียกใช้ service ของตัว Prisma ซึ่งทำให้เรา development application ได้ง่ายมากขึ้นและช่วยลด เวลา ไปได้มาก
(ปล. ถ้าอ่านแล้ว งง ก็ขอประทานโทษมา ณ ที่นี้ ด้วยนะครับบบบบบ 🙏🙏🙏🙏🙏🙏)
(ปล. 2 สามารถเข้าไปดูโค้ด ในนี้ได้เลยครับ click)

--

--