NestJS ตั้งแต่ศูนย์: ระบบจัดการหนังสือ

คู่มือ NestJS, Next.js และ CRUD พร้อมตัวอย่างโปรเจกต์ BookShelf ที่รัน API และ SQLite จริงด้วย Docker Compose

📚 BookShelf อยู่ใน GitHub repo — ดาวน์โหลดได้

ไม่ต้องสร้างโปรเจกต์ใหม่: โค้ด BookShelf ทั้ง frontend และ backend อยู่ใน repository MANAPHAT56/web ดาวน์โหลด ZIP จาก GitHub หรือ clone repo แล้วเข้าโฟลเดอร์โปรเจกต์ตามด้านล่าง

1ตำแหน่งไฟล์และดาวน์โหลด

ส่วนระบบตำแหน่งใน repo
คู่มือและคำสั่งติดตั้งindex.html, README.md, docker-compose.yml
Backend / APIbook-review-backend/book-review-api/
ฐานข้อมูลและ migrationbook-review-backend/book-review-api/prisma/
Frontend / Next.jsbook-review-frontend/book-review-frontend (Unzipped Files)/

หากใช้ Git ให้ดาวน์โหลดทั้ง repository เพื่อให้ Docker Compose เห็นทั้ง frontend และ backend:

git clone https://github.com/MANAPHAT56/web.git
cd web

ไฟล์ที่ดาวน์โหลดจาก repo อาจยังไม่มี .env เพราะเป็นค่าตั้งค่าเฉพาะเครื่อง ให้สร้างจาก .env.example ในขั้นตอนถัดไป

🚀 เปิด BookShelf ด้วย Docker

เริ่มจากโฟลเดอร์รากของ repo ที่มี docker-compose.yml ระบบจะเปิด Next.js, NestJS API และ SQLite พร้อม migration และ persistent volumes ให้เอง

2ติดตั้งและเปิดระบบบน Windows

ติดตั้ง Docker Desktop และเปิด Docker Engine ก่อน จากนั้นเปิด PowerShell ที่โฟลเดอร์โปรเจกต์ (เช่น C:\Users\ttpho\Downloads\api-exam)

Copy-Item .env.example .env
docker compose up --build -d
docker compose ps

เปิดหน้าเว็บที่ http://localhost:3001 และ API health check ที่ http://localhost:3000/health เมื่อ API พร้อมจะตอบ {"status":"ok"} การเริ่ม API จะรัน prisma migrate deploy เพื่อสร้างตารางจาก migration โดยอัตโนมัติ

3ทดสอบ CRUD และตรวจฐานข้อมูลจริง

สร้างหนังสือและรีวิวผ่าน REST API แล้วอ่านรายการกลับมาได้ คำสั่ง PowerShell ตัวอย่าง:

$book = Invoke-RestMethod -Method Post http://localhost:3000/books `
  -ContentType 'application/json' `
  -Body '{"title":"Docker Test","author":"API Check"}'

$review = Invoke-RestMethod -Method Post "http://localhost:3000/books/$($book.id)/reviews" `
  -ContentType 'application/json' `
  -Body '{"rating":5,"content":"บันทึกจาก API"}'

Invoke-RestMethod -Method Patch "http://localhost:3000/books/$($book.id)" `
  -ContentType 'application/json' -Body '{"title":"Updated Docker Test"}'

Invoke-RestMethod "http://localhost:3000/books/$($book.id)" | ConvertTo-Json -Depth 5

ตรวจแถวใน SQLite ผ่าน Prisma Client ภายใน API container ได้อีกทาง:

docker compose exec api node -e 'const {PrismaClient}=require("@prisma/client");const p=new PrismaClient();p.book.findMany({include:{reviews:true}}).then(rows=>console.log(JSON.stringify(rows))).finally(()=>p.$disconnect())'

ถ้าค่าที่อ่านได้มีหนังสือและรีวิวที่เพิ่งสร้าง แปลว่าข้อมูล persist อยู่ในฐานข้อมูล ไม่ได้อยู่แค่ใน response จาก API

4Endpoints และการเก็บข้อมูล

MethodPathการทำงาน
POST / GET/booksเพิ่มหนังสือ / ดูรายการหนังสือและรีวิว
GET / PATCH / DELETE/books/:idอ่าน / แก้ไข / ลบหนังสือ (ลบรีวิวที่เกี่ยวข้องตาม)
POST / GET/books/:bookId/reviewsเพิ่ม / ดูรีวิว
PATCH / DELETE/books/:bookId/reviews/:reviewIdแก้ไข / ลบรีวิว
POST/books/uploadอัปโหลดปก JPG, PNG หรือ WebP ขนาดไม่เกิน 5 MB
GET/healthตรวจสถานะ API

ฐานข้อมูลอยู่ใน volume book-review-data และไฟล์ภาพอยู่ใน book-review-uploads หยุดระบบโดยไม่ลบข้อมูลด้วยคำสั่งนี้:

docker compose down

ลบข้อมูลถาวรและไฟล์ภาพด้วย docker compose down --volumes เท่านั้น คำสั่งนี้ลบข้อมูลทั้งหมดใน volumes

เริ่ม NestJS จากศูนย์ (กรณีไม่ได้ใช้ BookShelf)

1ติดตั้ง Node.js

ดาวน์โหลดเวอร์ชัน LTS จาก nodejs.org (npm จะติดมาด้วย) แล้วเช็คใน terminal

node -v
npm -v

2ติดตั้ง Nest CLI

เครื่องมือบรรทัดคำสั่งของ NestJS ติดตั้งครั้งเดียวใช้ได้ทุกโปรเจกต์

npm i -g @nestjs/cli
nest --version

ถ้าขึ้น nest is not recognized ให้ปิดแล้วเปิด terminal ใหม่ ส่วน Windows PowerShell ที่ติด execution policy ให้ใช้ Command Prompt แทน

3สร้างโฟลเดอร์และโปรเจกต์

เลือกที่เก็บงาน แล้วให้ Nest สร้างโฟลเดอร์โปรเจกต์ให้เอง (ไม่ต้อง mkdir ชื่อโปรเจกต์) เลือก npm เมื่อถูกถาม

mkdir projects && cd projects
nest new library-api
cd library-api

4รันครั้งแรก

npm run start:dev

เปิด http://localhost:3000 จะเห็น Hello World! โหมดนี้รีสตาร์ทเองทุกครั้งที่เซฟไฟล์ (หยุดด้วย Ctrl+C)

5ติดตั้งแพ็กเกจเพิ่ม

npm install class-validator class-transformer @nestjs/swagger

สองตัวแรกใช้ตรวจความถูกต้องของข้อมูล (ตอบ 400) ตัวที่สามสร้างหน้าเอกสาร API ที่ /docs

6สร้างโครง CRUD

nest g resource books

เลือก REST API และตอบ Yes ตอนถามเรื่อง CRUD entry points จะได้ module, controller, service, DTO และ entity ครบ จากนั้นนำโค้ดของ books.controller.ts, books.service.ts, book.dto.ts ที่ผมให้ไว้ก่อนหน้านี้มาวางทับ

ตัวสร้างอัตโนมัติใช้ PATCH สำหรับแก้ไข แต่โจทย์ของเราใช้ PUT จึงต้องแก้ใน controller ตามโค้ดที่ให้ไว้

ไฟล์หน้าที่
books.controller.tsกำหนด route GET/POST/PUT/DELETE
books.service.tsตรรกะและข้อมูลจำลอง
dto/book.dto.tsรูปแบบข้อมูลและ validation

7เปิด Validation และ Swagger ใน main.ts

import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  const cfg = new DocumentBuilder().setTitle('Library API').build();
  SwaggerModule.setup('docs', app, SwaggerModule.createDocument(app, cfg));
  await app.listen(3000);
}
bootstrap();

8ทดสอบ

เปิด http://localhost:3000/docs แล้วกด Try it out หรือใช้ curl

curl http://localhost:3000/books
curl -i http://localhost:3000/books/999   # ได้ 404
คำสั่งใช้ทำอะไร
npm run start:devรันตอนพัฒนา (auto reload)
npm run buildคอมไพล์เป็นโฟลเดอร์ dist
npm run start:prodรันจากโค้ดที่ build แล้ว
npm run testรันเทสต์

ปัญหาที่พบบ่อย

Cannot find module './dto/book.dto' แปลว่าไฟล์ไม่ได้อยู่ที่ src/books/dto/book.dto.ts หรือชื่อสะกดไม่ตรง
EADDRINUSE แปลว่าพอร์ต 3000 ถูกใช้อยู่ ให้ปิดโปรเจกต์เดิมหรือเปลี่ยนพอร์ตใน listen()

การใช้ Swagger

Swagger ทำอะไรได้

สร้างหน้าเอกสาร API ให้อัตโนมัติจากโค้ด เปิดที่ /docs เห็นทุก endpoint และกด Try it out เพื่อยิง API ทดสอบได้เลย (ตั้งค่าใน main.ts ตามขั้นที่ 7 ด้านบน)

DTO ใส่ @ApiProperty({ example: ... }) เพื่อให้ช่อง Request body มีตัวอย่างข้อมูล

Controller ใส่ decorator เหล่านี้เพื่อบอกสถานะที่ตอบกลับ

import { ApiTags, ApiOperation, ApiOkResponse,
  ApiCreatedResponse, ApiNotFoundResponse } from '@nestjs/swagger';

@ApiTags('books')            // จัดกลุ่มหัวข้อ
@Controller('books')
export class BooksController {
  @Get(':id')
  @ApiOperation({ summary: 'ดึงหนังสือเล่มเดียว' })
  @ApiOkResponse({ description: 'พบหนังสือ (200)' })
  @ApiNotFoundResponse({ description: 'ไม่พบหนังสือ (404)' })
  findOne(@Param('id', ParseIntPipe) id: number) { ... }

  @Post()
  @ApiCreatedResponse({ description: 'สร้างสำเร็จ (201)' })
  create(@Body() dto: BookDto) { ... }
}

ถ้าอยากไม่ต้องเขียน @ApiProperty ทุกฟิลด์ ให้เปิด CLI plugin โดยเพิ่ม @nestjs/swagger ใน nest-cli.json (ดูลิงก์หัวข้อ “เรื่อง Swagger” ท้ายหน้า)

🔁 Gen โค้ดจาก OpenAPI / Postman (ไม่ต้องเริ่มจาก 0)

อาจารย์ให้ Swagger (OpenAPI) มาแล้ว ใช้ตัว generator สร้างโครง controller และ DTO ให้ก่อน จากนั้นค่อยเติมตรรกะใน service คำสั่งด้านล่างรวบรวมจากเอกสารของแต่ละเครื่องมือ ผมยังไม่ได้ลองรันเอง ถ้า error ให้เทียบกับ README ของแพ็กเกจนั้น (ลิงก์ท้ายหัวข้อ)

0ดูก่อนว่าได้อะไรมาจากอาจารย์

สิ่งที่ได้มาทำอะไรต่อ
ไฟล์ openapi.yaml / openapi.json (หรือ swagger.json)ไปขั้น 2 ได้เลย
Postman collection (.json)แปลงเป็น OpenAPI ก่อนที่ขั้น 1 แล้วไปขั้น 2
ลิงก์หน้า Swagger UIถ้าเป็น NestJS ลองเปิด /docs-json ต่อท้ายพาธ Swagger (เช่น http://localhost:3000/docs-json) แล้วเซฟเป็นไฟล์ ถ้าเป็นเซิร์ฟเวอร์อื่นพาธอาจต่างออกไป ดูลิงก์ใต้ชื่อเอกสารในหน้า Swagger UI

1แปลง Postman collection เป็น OpenAPI

ใช้แพ็กเกจ postman-to-openapi (รองรับ collection v2.0/v2.1 แปลงเป็น OpenAPI 3.0)

npm i -g postman-to-openapi
p2o ./collection.json -f ./openapi.yml

Postman collection คือตัวอย่าง request ไม่ใช่สัญญา API ที่สมบูรณ์ schema ที่ได้เป็นการเดาจากตัวอย่าง ต้องเปิดไฟล์ตรวจเองว่าชนิดข้อมูล field ที่ optional และ response ผิดพลาด (400/404) ครบหรือยัง

2Gen โครง NestJS จาก OpenAPI

ตัวเลือก A: @snow-tzu/nest-openapi-code-generator แบบ contract-first สร้าง controller, DTO (มี class-validator และ @ApiProperty ให้) จาก OpenAPI 3.1

cd library-api
npm install @snow-tzu/nest-openapi-code-generator
mkdir specs
# วางไฟล์ spec ไว้ที่ specs/books.openapi.yaml
npx openapi-generate --specs ./specs --output ./src/generated

ตัวสร้างมีโหมด --watch ที่ gen ใหม่เมื่อไฟล์ spec เปลี่ยน และตั้งค่าเพิ่มผ่าน openapi.config.ts ได้ (specsDir, outputDir, generateControllers, generateDtos) ชื่อคลาสที่ได้อิงจากชื่อไฟล์ spec จึงควรตั้งชื่อเป็น books.openapi.yaml

ตัวเลือก B: @fresha/openapi-codegen สร้าง module, controller, action และ DTO ตามแนวทางของ NestJS

npm install @fresha/openapi-codegen
npx fresha-openapi-codegen server-nestjs --input ./openapi.yaml --output .

ข้อควรระวัง: generator typescript-nestjs ของ OpenAPI Generator (openapi-generator-cli) เป็น ฝั่ง client และยังเป็น experimental ไม่ใช่ตัวสร้างโครง server ดังนั้นสำหรับ backend ให้ใช้ตัวเลือก A หรือ B

3ต่อโค้ดที่ gen เข้ากับโปรเจกต์

โครงไฟล์ที่ได้ขึ้นกับเครื่องมือและเวอร์ชัน เปิดโฟลเดอร์ผลลัพธ์ดูก่อน แล้วทำตามลำดับนี้

ลำดับสิ่งที่ทำ
1เก็บโค้ดที่ gen ไว้ในโฟลเดอร์แยก เช่น src/generated และพยายามไม่แก้ตรงๆ เพราะ gen ใหม่อาจเขียนทับ
2นำ module หรือ controller ที่ได้ไป import ใน app.module.ts
3เติมตรรกะที่เป็นข้อมูลจำลอง (หรือต่อฐานข้อมูล) ใน service โดยนำโค้ดจาก books.service.ts ด้านล่างไปปรับ
4รัน npm run start:dev เปิด /docs-json เทียบกับ spec ของอาจารย์ ว่า path, method, ชื่อ field และ status code ตรงกัน

4ตัวอย่าง spec ของระบบ books

ถ้ายังไม่มีไฟล์จากอาจารย์ ใช้ไฟล์นี้ทดลอง generator ได้ (ตรงกับ endpoint และ field ในโค้ดด้านล่าง) วางเป็น specs/books.openapi.yaml

5Gen โค้ดฝั่ง Next.js จาก spec เดียวกัน

ใช้ spec ตัวเดิมสร้างฟังก์ชันเรียก API พร้อมชนิดข้อมูล แทนการเขียน lib/api.ts เอง

cd library-web
# orval: สร้าง client พร้อมชนิดข้อมูลจาก OpenAPI v3 หรือ Swagger v2
npm i -D orval
npx orval --input ../library-api/specs/books.openapi.yaml --output ./lib/generated/books.ts

# หรือ openapi-typescript: สร้างเฉพาะชนิดข้อมูล TypeScript
npx openapi-typescript ../library-api/specs/books.openapi.yaml -o ./lib/schema.d.ts

อีกทางคือ OpenAPI Generator (ต้องมี Java) เช่น npx @openapitools/openapi-generator-cli generate -i openapi.yaml -g typescript-axios -o ./client

6ไปทางกลับ: สร้าง Postman collection จาก OpenAPI

เอาไว้ทดสอบ API โดยไม่ต้องสร้าง request ทีละอัน

วิธีทำอย่างไร
ในแอป Postmanกด Import แล้วเลือกไฟล์ OpenAPI (รองรับ OpenAPI 2.0, 3.0, 3.1) ได้ collection ที่มีโฟลเดอร์ request และตัวอย่าง response
CLI (เก็บไฟล์ในโปรเจกต์)npm i -g openapi-to-postmanv2 แล้ว openapi2postmanv2 -s openapi.yml -o postman-collection.json -p
Postman APIส่ง POST https://api.getpostman.com/import/openapi เพื่อนำเข้า OpenAPI เป็น collection ใหม่ (ต้องใช้ API key)
ลิงก์ของเครื่องมือในหัวข้อนี้
nest-openapi-code-generatorตัวเลือก A: gen controller และ DTO จาก OpenAPI 3.1github.com/ganesanarun/nest-openapi-code-generator @fresha/openapi-codegen-server-nestjsตัวเลือก B: คำสั่ง server-nestjsnpmjs.com/package/@fresha/openapi-codegen-server-nestjs postman-to-openapiแปลง Postman collection เป็น OpenAPI 3.0npmjs.com/package/postman-to-openapi Postman: Generate collectionsสร้าง collection จาก OpenAPI ในแอป Postmanlearning.postman.com/docs/design-apis/specifications/generate-collections Postman API: Import OpenAPIนำเข้า OpenAPI ผ่าน APIlearning.postman.com/api-docs/api-reference/import/open-api-definition orvalgen client พร้อมชนิดข้อมูลจาก OpenAPI v3 / Swagger v2 (เอกสารที่ orval.dev)github.com/orval-labs/orval DEV: Generate TypeScript clients from OpenAPIตัวอย่าง gen client จาก /api-json ของ NestJS ด้วย openapi-generator-clidev.to/arnaudcortisse/…-28mk

🧱 โค้ดเต็มฝั่ง Backend (NestJS) ระบบ books

ไฟล์ครบทุกตัวของโปรเจกต์ library-api ที่สร้างด้วย nest g resource books วางทับได้เลย ข้อมูลเก็บในหน่วยความจำ (รีสตาร์ตแล้วหาย) field ใช้ title, author, price ถ้า DTO เดิมของคุณต่างจากนี้ให้ปรับให้ตรงกัน

โครงไฟล์

library-api/
└─ src/
   ├─ main.ts
   ├─ app.module.ts
   └─ books/
      ├─ books.module.ts
      ├─ books.controller.ts
      ├─ books.service.ts
      ├─ dto/book.dto.ts
      └─ entities/book.entity.ts

ไฟล์ใน src/books

app.module.ts และ main.ts

ใน main.ts เพิ่ม enableCors เพื่อให้ Next.js (พอร์ต 3001) เรียก API ได้ และเปิด whitelist ให้ตัด field แปลกปลอมทิ้ง

🖥️ ฝั่ง Frontend (Next.js) ต่อกับ books

ใช้ App Router + TypeScript หน้าแรกเป็น Server Component ดึงรายการหนังสือ ส่วนฟอร์มเพิ่ม/แก้ไขและปุ่มลบเป็น Client Component

1สร้างโปรเจกต์ Next.js

เปิด terminal ใหม่ ออกจากโฟลเดอร์ library-api แล้วสร้างโปรเจกต์ข้างๆ (ถ้ามีคำถามเพิ่ม เช่น React Compiler หรือ Turbopack ให้กด Enter ใช้ค่าเริ่มต้น)

cd ..
npx create-next-app@latest library-web --typescript --app --no-tailwind --eslint --no-src-dir --import-alias "@/*"
cd library-web

2ตั้งพอร์ตเป็น 3001

Nest ใช้พอร์ต 3000 อยู่แล้ว แก้ส่วน scripts ใน package.json

แล้วสร้างไฟล์ .env.local ที่รากโปรเจกต์ (ค่าที่ขึ้นต้น NEXT_PUBLIC_ ใช้ได้ทั้งฝั่ง server และ browser)

3โครงไฟล์

library-web/
├─ .env.local
├─ lib/api.ts
├─ components/
│  ├─ BookForm.tsx
│  └─ DeleteButton.tsx
└─ app/
   ├─ globals.css
   ├─ layout.tsx
   ├─ page.tsx                  (รายการ)
   └─ books/
      ├─ new/page.tsx           (เพิ่ม)
      └─ [id]/edit/page.tsx     (แก้ไข)

สร้างโฟลเดอร์ lib และ components ที่รากโปรเจกต์เอง ส่วนไฟล์ใน app ให้วางทับไฟล์เดิม (ลบ app/page.module.css ทิ้งได้)

4ตัวเรียก API

5Components (Client)

6หน้าเว็บใน app/

7รันทั้งสองฝั่งและทดสอบ

เปิด 2 terminal แยกกัน

# terminal 1 (backend พอร์ต 3000)
cd library-api
npm run start:dev

# terminal 2 (frontend พอร์ต 3001)
cd library-web
npm run dev

เปิด http://localhost:3001 ควรเห็นหนังสือ 2 เล่มจาก Nest ลองกดเพิ่ม แก้ไข และลบ แล้วเช็คที่ http://localhost:3000/docs ว่าข้อมูลตรงกัน

อาการสาเหตุและวิธีแก้
fetch failed / ECONNREFUSEDBackend ยังไม่รัน หรือ NEXT_PUBLIC_API_URL ผิด (แก้ .env.local แล้วต้องรีสตาร์ต npm run dev)
CORS error ใน browserลืม enableCors ใน main.ts หรือยังไม่รีสตาร์ต Nest
กดบันทึกแล้วได้ 400ข้อมูลไม่ผ่าน validation เช่น ชื่อว่าง หรือราคาติดลบ
Cannot find module '@/lib/api'โฟลเดอร์ lib ต้องอยู่ที่รากโปรเจกต์ (ไม่ใช่ใน app) และ import alias ต้องเป็น @/*

⚡ ฟังก์ชันของ Next.js ที่ใช้บ่อย

กดหัวข้อเพื่อดูฟังก์ชัน ตัวอย่าง และผลลัพธ์ อ้างอิงจาก App Router ถ้าใช้คนละเวอร์ชัน (บางส่วนเปลี่ยนใน Next 15 และ 16) ให้เทียบกับ nextjs.org/docs

📘 ฟังก์ชันจัดการตัวแปรแต่ละชนิดใน TypeScript

กดหัวข้อเพื่อเปิดดูตาราง ฟังก์ชัน ตัวอย่าง และผลลัพธ์ แต่ละแถวเป็นอิสระต่อกัน (ไม่ต่อเนื่องจากแถวก่อนหน้า) บางฟังก์ชัน เช่น replaceAll, at, Promise.any ต้องตั้ง target หรือ lib ใน tsconfig เป็น ES2022 ขึ้นไป (โปรเจกต์ NestJS รุ่นใหม่ตั้งไว้ให้แล้ว)

พบ 9 ลิงก์ (บทความไทยมีน้อย) หลายชิ้นเก่า 2–5 ปี คำสั่งบางอย่างอาจเปลี่ยนไปแล้ว ให้เทียบกับ docs.nestjs.com

ตรงเรื่อง CRUD
1. สร้าง RESTful APIs ด้วย NestJS ตอนที่ 4Medium: ทำ CRUD กับฐานข้อมูลด้วย TypeORM แยกตามความสัมพันธ์ของตาราง พร้อมเตือนจุดที่ error บ่อย (เป็นตอนที่ 4 ของชุด)medium.com/@slil.puangpoom 2. พัฒนา CRUD + Role-based Authentication ตอนที่ 1Medium: สอน Create/Read/Update/Delete ของ user อธิบาย DTO และการกำหนด path ใกล้เคียงโจทย์ของเรามากที่สุดmedium.com/@erika.snp 3. สร้าง RESTful API ด้วย NestJS และ MongoDBmeesiri.com: บล็อกบริษัท เนื้อหาเชิงภาพรวม ตั้งแต่ติดตั้ง NestJS CLI ถึงต่อ MongoDBmeesiri.com/blog/…/sraang-restful-api-dwy-nestjs-aela-mongodb-2104 4. พื้นฐาน NestJS ทำ API CRUD ข้อมูล MySQLYouTube: วิดีโอ live code เหมาะกับคนชอบดูมากกว่าอ่าน (ลงมาประมาณ 4–5 ปีแล้ว)youtube.com/watch?v=zY2dU54X08E 5. คอร์ส RESTful API NestJS + TypeORM + GraphQL + MySQLSkillLane: คอร์สออนไลน์ภาษาไทย สอน REST API, TypeORM และล็อกอินด้วย JWT (ยังไม่ทราบว่าต้องเสียเงินหรือไม่)skilllane.com/courses/RESTful-API-NestJS-TypeORM-GraphQL-MySQL
เกี่ยวข้อง แต่ไม่ใช่ CRUD ตรงๆ
6. Learning Management System (Prisma + PostgreSQL + Docker)GitHub: โปรเจกต์ตัวอย่างพร้อม README ภาษาไทย เหมาะดูโครงสร้างงานจริง (ผู้เขียนบอกว่ายังไม่มี validation ละเอียด)github.com/nut2567/Learning_Management_System_PostgreSql 7. สร้าง API ด้วย NestJS GraphQL ฉบับนักพัฒนาไทยmeesiri.com: ทำ API ด้วย GraphQL แทน RESTmeesiri.com/blog/…/sraang-api-dwy-nestjs-graphql-…-1989 8. รวมบทความ Node.js ของ meesiri.comหน้ารวมบทความ มี “คู่มือสร้าง RESTful API ด้วย NestJS ฉบับนักพัฒนาไทย” ต้องกดเลือกจากหน้านี้meesiri.com/blog/tag/node-js-814
เรื่อง Swagger
9. Mintelligence: NestJS OpenApi (Swagger)Medium: เรื่อง Swagger (เก่า ใช้ชื่อ ApiModelProperty ปัจจุบันใช้ ApiProperty)medium.com/mintelligence/openapi-4824dba1ab86