iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0

昨天介紹過了怎麼在 nest.js 裡面建立 chp555 MODE,今天我們來介紹如何在 NestJS 中建立 CRUD 操作,基本 CRUD 功能,包括創建報告、查詢報告、更新報告和移除報告。

CHP555 報告

首先,我們先來建立 Chp555 報告的 ControllerService。Controller 負責接收 HTTP 請求並調用相應的服務方法,Service 則負責處理業務邏輯並與資料庫進行互動。

Controller

  • 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 方法在此定義
  }

Service

  • Injectable 來自 @nestjs/common,用來標記這個服務類別可以被注入。
  • NotFoundException 用來在資料查詢不到時丟出 404 錯誤,提供更好的錯誤處理。
  • InjectModel 來自 @nestjs/mongoose,用來注入 Mongoose 的資料模型。
  • Model 則是 Mongoose 提供的,用來與 MongoDB 進行互動。
  • Chp555ReportParty 分別是我們定義的報告與相關資料的模式,用來定義資料結構。
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 方法在此定義
  }

API

建立報告

在建立報告的部分,create 方法負責接收來自用戶端的資料,並將其存入資料庫。這裡我們會同時建立三個 Party 資料作為報告的一部分,並將這些 Party 的 ID 保存到報告中。

我這邊採用一開始建立報告的時候就直接生成 三個 party的資料,後面採用更新填入。

Controller

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,
      },
    };
  }

Service

  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();
  }

取得報告

對於查詢報告的部分,我們可以選擇查詢單個報告或所有報告。單個報告主要用來使用於查看單個報告或編輯。所有報告,可用來看報告記錄列表。但其實不應該傳這麼多資料回去。

Controller

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,
      };
    }
  }

Service

取得全部

  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 方法,更新指定的報告內容。

Controller

router: /chp555-report
method: patch

  @Patch('report')
  async update(@Body() updateReportDto: any) {
    const data = await this.chp555ReportService.update(updateReportDto);
    return {
      status: 'success',
      data,
    };
  }

Service

這邊先做簡單的錯誤處理,找不到報告的時候拋出錯誤。

  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;
  }

移除報告

移除報告

Controller

router: /chp555-report
method: delet

  @Delete(':id')
  async remove(@Param('id') id: string) {
    return this.chp555ReportService.remove(id);
  }

service

  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`);
    }
  }

API 表格

回傳的資料我目前還沒詳細定義,就是把 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' }

完整程式碼

controller

這邊是完整程式碼。

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);
  }
}

service

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鐵人


上一篇
[Day27] NestJS 與 MongoDB 報告系統實作:資料庫模型設計
下一篇
[Day29] APP串接表單 CRUD
系列文
30天 使用chatGPT輔助學習APP完成接案任務委託30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言