昨天介紹過了怎麼在 nest.js 裡面建立 chp555 MODE,今天我們來介紹如何在 NestJS 中建立 CRUD 操作,基本 CRUD 功能,包括創建報告、查詢報告、更新報告和移除報告。
首先,我們先來建立 Chp555 報告的 Controller 與 Service。Controller 負責接收 HTTP 請求並調用相應的服務方法,Service 則負責處理業務邏輯並與資料庫進行互動。
AuthGuard
是用來保護路由的守衛,在這裡我們使用 JWT 驗證,確保只有授權的用戶才能執行操作。Chp555ReportService
則是我們建立的 Service,用來處理報告的業務邏輯。import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Query,
UseGuards,
} from '@nestjs/common';
import { Chp555ReportService } from './service/chp555Report.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('chp555-report')
export class Chp555ReportController {
constructor(private readonly chp555ReportService: Chp555ReportService) {}
.....// 其他 CRUD 方法在此定義
}
Injectable
來自 @nestjs/common
,用來標記這個服務類別可以被注入。NotFoundException
用來在資料查詢不到時丟出 404 錯誤,提供更好的錯誤處理。InjectModel
來自 @nestjs/mongoose
,用來注入 Mongoose 的資料模型。Model
則是 Mongoose 提供的,用來與 MongoDB 進行互動。Chp555Report
和 Party
分別是我們定義的報告與相關資料的模式,用來定義資料結構。import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Chp555Report } from '../schemas/CHP555Report/chp555Report.schema';
import { Party } from '../schemas/CHP555Report/Party/party.schema';
@Injectable()
export class Chp555ReportService {
constructor(
@InjectModel(Chp555Report.name)
private readonly chp555ReportModel: Model<Chp555Report>,
@InjectModel(Party.name)
private readonly partyModel: Model<Party>,
) {}
.... // 其他 CRUD 方法在此定義
}
在建立報告的部分,create
方法負責接收來自用戶端的資料,並將其存入資料庫。這裡我們會同時建立三個 Party
資料作為報告的一部分,並將這些 Party
的 ID 保存到報告中。
我這邊採用一開始建立報告的時候就直接生成 三個 party的資料,後面採用更新填入。
router: /chp555-report
method: post
@Post()
async create(@Body() createReportDto: any) {
const data = await this.chp555ReportService.create(createReportDto);
return {
status: 'success',
data: {
reportId: data._id,
},
};
}
async create(createReportDto: any): Promise<Chp555Report> {
const parties = [];
for (let i = 0; i < 3; i++) {
const newParty = new this.partyModel({
order: i + 1,
});
const savedParty = await newParty.save();
parties.push(savedParty._id);
}
const createdReport = new this.chp555ReportModel({
...createReportDto,
partyies: parties,
});
return createdReport.save();
}
對於查詢報告的部分,我們可以選擇查詢單個報告或所有報告。單個報告主要用來使用於查看單個報告或編輯。所有報告,可用來看報告記錄列表。但其實不應該傳這麼多資料回去。
router: /chp555-report/:id
method: get
@Get()
async find(@Query('reportId') reportId?: string) {
if (reportId) {
// 如果有 reportId,查詢單個報告
const data = await this.chp555ReportService.findOne(reportId);
return {
status: 'success',
data,
};
} else {
// 如果没有 reportId,查詢所有報告
const data = await this.chp555ReportService.findAll();
return {
status: 'success',
data,
};
}
}
async findAll(): Promise<Chp555Report[]> {
return this.chp555ReportModel.find().exec();
}
async findOne(id: string): Promise<Chp555Report> {
const report = await this.chp555ReportModel.findById(id).exec();
if (!report) {
throw new NotFoundException(`Report with ID ${id} not found`);
}
return report;
}
當需要更新報告時,可以使用 PATCH
方法,更新指定的報告內容。
router: /chp555-report
method: patch
@Patch('report')
async update(@Body() updateReportDto: any) {
const data = await this.chp555ReportService.update(updateReportDto);
return {
status: 'success',
data,
};
}
這邊先做簡單的錯誤處理,找不到報告的時候拋出錯誤。
async update(updateReportDto: any): Promise<Chp555Report> {
const id = updateReportDto.id;
const updatedReport = await this.chp555ReportModel
.findByIdAndUpdate(id, updateReportDto, { new: true })
.exec();
if (!updatedReport) {
throw new NotFoundException(`Report with ID ${id} not found`);
}
return updatedReport;
}
移除報告
router: /chp555-report
method: delet
@Delete(':id')
async remove(@Param('id') id: string) {
return this.chp555ReportService.remove(id);
}
async remove(id: string): Promise<void> {
const result = await this.chp555ReportModel.findByIdAndDelete(id).exec();
if (!result) {
throw new NotFoundException(`Report with ID ${id} not found`);
}
}
回傳的資料我目前還沒詳細定義,就是把 Report的 model直接丟出來。
方法 | 路由 | 描述 | 請求參數 | 回應格式 |
---|---|---|---|---|
POST | /chp555-report | 建立報告 | createReportDto (Body) |
{ status: 'success', data: { reportId: string }} |
GET | /chp555-report | 查詢所有報告 | - | { status: 'success', data: Report[] } |
GET | /chp555-report | 查詢單個報告 | reportId (Query, 可選) |
{ status: 'success', data: Report } |
PATCH | /chp555-report/report | 更新指定報告 | updateReportDto (Body) |
{ status: 'success', data: Report } |
DELETE | /chp555-report/ | 刪除指定報告 | id (Path) |
{ status: 'success' } |
這邊是完整程式碼。
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Query,
UseGuards,
} from '@nestjs/common';
import { Chp555ReportService } from './service/chp555Report.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('chp555-report')
export class Chp555ReportController {
constructor(private readonly chp555ReportService: Chp555ReportService) {}
@UseGuards(AuthGuard('jwt'))
@Post()
async create(@Body() createReportDto: any) {
const data = await this.chp555ReportService.create(createReportDto);
return {
status: 'success',
data: {
reportId: data._id,
},
};
}
@UseGuards(AuthGuard('jwt'))
@Get()
async find(@Query('reportId') reportId?: string) {
if (reportId) {
const data = await this.chp555ReportService.findOne(reportId);
return {
status: 'success',
data,
};
} else {
const data = await this.chp555ReportService.findAll();
return {
status: 'success',
data,
};
}
}
@UseGuards(AuthGuard('jwt'))
@Patch('report')
async update(@Body() updateReportDto: any) {
const data = await this.chp555ReportService.update(updateReportDto);
return {
status: 'success',
data,
};
}
@UseGuards(AuthGuard('jwt'))
@Delete(':id')
async remove(@Param('id') id: string) {
return this.chp555ReportService.remove(id);
}
}
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Chp555Report } from '../schemas/CHP555Report/chp555Report.schema';
import { Party } from '../schemas/CHP555Report/Party/party.schema';
import {
SpecialConditionEnum,
SpecialConditionName,
} from '../../const/eumns/chp555Report';
@Injectable()
export class Chp555ReportService {
constructor(
@InjectModel(Chp555Report.name)
private readonly chp555ReportModel: Model<Chp555Report>,
@InjectModel(Party.name)
private readonly partyModel: Model<Party>,
) {}
async create(createReportDto: any): Promise<Chp555Report> {
const parties = [];
for (let i = 0; i < 3; i++) {
const newParty = new this.partyModel({
order: i + 1,
});
const savedParty = await newParty.save();
parties.push(savedParty._id);
}
const createdReport = new this.chp555ReportModel({
...createReportDto,
partyies: parties,
});
return createdReport.save();
}
async findAll(): Promise<Chp555Report[]> {
return this.chp555ReportModel.find().exec();
}
async findOne(id: string): Promise<Chp555Report> {
const report = await this.chp555ReportModel.findById(id).exec();
if (!report) {
throw new NotFoundException(`Report with ID ${id} not found`);
}
return report;
}
async update(updateReportDto: any): Promise<Chp555Report> {
const id = updateReportDto.id;
const updatedReport = await this.chp555ReportModel
.findByIdAndUpdate(id, updateReportDto, { new: true })
.exec();
if (!updatedReport) {
throw new NotFoundException(`Report with ID ${id} not found`);
}
return updatedReport;
}
async remove(id: string): Promise<void> {
const result = await this.chp555ReportModel.findByIdAndDelete(id).exec();
if (!result) {
throw new NotFoundException(`Report with ID ${id} not found`);
}
}
}
實作完成建議要使用 postman做測試,這樣才會知道是否符合需求。明天來實作串接到APP
#it鐵人