跳至主要內容

TypeScript 實戰:後端驗證與中間件

約 5 分鐘

cover

前言

在開發後端應用程式時,資料驗證和中間件的設計是非常重要的。這不僅能確保資料的正確性,也能提升 API 的穩定性。在這篇文章中,我們將使用與 TypeScript 很搭的 Zod 進行資料驗證,並撰寫一個簡單的 Express 中間件來處理錯誤。

Zod 套件

Zod 是一個功能強大的 TypeScript 驗證套件,它允許我們用簡潔的語法來定義資料結構和約束。相比其他驗證庫,Zod 更加貼合 TypeScript 的型別系統,並且支援推斷型別。這讓我們能夠從 Schema 中自動生成 TypeScript 型別,減少重複代碼。更多資訊可以查看 Zod 的文檔

首先我們安裝 Zod

npm i zod

撰寫驗證

在這裡,我們使用 Zod 來驗證我們要存的 Task 資料。Task 包含以下幾個欄位:標題、描述、狀態、以及預估的 Story Point。透過 z.object 定義一個 Zod Schema,並利用 z.infer 的方式來生成對應的 TypeScript 型別。

import { z } from 'zod'
 
// ...
 
export const inputTaskSchema = z.object({
  title: z.string().min(1),
  description: z.string().optional(),
  status: z.enum(['new', 'active', 'completed']).default('new'),
  storyPoint: z.number().optional(),
})
 
export interface TaskType extends z.infer<typeof inputTaskSchema> {
  id: string
}
 
export default class TaskModel extends AbstractBaseModel<TaskType> {
  collection = 'task'
 
  validateData(data: unknown): z.infer<typeof inputTaskSchema> {
    return inputTaskSchema.parse(data)
  }
}

撰寫新增邏輯

接下來,我們在 Controller 撰寫一個 createTask 函式,負責新增一個 Task。這裡透過 taskModel.validateData 來驗證傳入的資料,確保資料符合 Schema 的約束。

// ...
 
export async function createTask(req: Request<{}, {}, TaskType>, res: Response<{ id: string }>, next: NextFunction) {
  try {
    const task = taskModel.validateData(req.body)
    const id = await taskModel.create(task)
    res.status(201).json({ id })
  }
  catch (error) {
    next(error)
  }
}

撰寫中間件(middleware)

在 Express 中,中間件(middleware)是處理請求和響應的一個重要組件,通過 use 調用,可以在請求處理的不同階段插入特定邏輯。

以下是三個都是中間件:

  • express.json 是 Express 提供的中間件,使用 express.json() 來解析 req.body 傳入的 JSON 請求。
  • 第一個參數如果有傳路徑,就會根據這個路徑來執行第二個參數的中間件。
  • 錯誤處理中間件,需要使用 4 參數(就算不使用 next,也是要定義出來),Express 就會將這個中間件視為錯誤處理中間件,我們將 Zod 的驗證錯誤以 400 狀態碼返回。
import express, { NextFunction, Request, Response } from 'express'
import { ZodError } from 'zod'
 
// ...
 
class Server {
  // ...
  start() {
    this.app.use(express.json())
 
    this.app.use('/task', taskRouter)
 
    this.app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
      if (err instanceof ZodError) {
        res.status(400).json({ message: err.errors })
      }
      else {
        res.status(500).json({ message: err.message })
      }
      next()
    })
 
    this.app.listen(port, () => {
      console.log(`Server is running on port ${port}`)
    })
  }
}
// ...

測試 API

我們可以使用 REST Client 工具來測試 API,將資料傳送至後端並驗證其是否新增成功。

打 API

若操作成功,可以在 db.json 檔案中檢查是否有新的 Task 被新增。

驗證 db.json

總結

這篇文章展示了如何透過 Zod 進行資料驗證,並撰寫 Express 的中間件來處理驗證錯誤。我們也撰寫完新增的邏輯,後面編輯與刪除的邏輯也是差不多的寫法,後端的部分大致上已經差不多了,下一篇我會介紹如何利用 TypeScript 5 新的裝飾器來重構我們的 Controller,並讓架構更精簡。

本篇程式碼變更可以看此 PR

相關文章

分享此文章
Johnson Mao

Johnson Mao

熱衷於分享技術、AI 與開發心得的軟體工程師。

留言