2022年4月7日木曜日

express のリクエストをクラスのオブジェクトにシリアライズするサンプルコード

express のリクエストをクラスのオブジェクトにシリアライズするサンプルコード

概要

TypeScript を使って型を定義しつつシリアライズします

環境

  • macOS 11.6.5
  • nodejs 17.8.0
  • express 4.17.3

サンプルコード

  • vim app.ts
import express from 'express'
const app = express()
const port = 3000

// ユーザプロファイルを管理するクラス
// 受け取ったリクエストはこのクラスのオブジェクトとして扱われる
// クラスはインタフェースを実装することで定義します 
// そうすることで定義したインタフェースを返り値などの型定義に使用できます
interface UserProfileType {
  name?: string,
  age?: string
}
class UserProfile implements UserProfileType {
  constructor(public name: string | undefined, public age: string | undefined) {
  }
  toJSON(): UserProfileType {
    return {
      name: this.name,
      age: this.age,
    }
  }
  // name と age が指定されているかの判定
  validate(): boolean {
    if (this.name === undefined || this.age === undefined) {
      return false
    } else {
      return true
    }
  }
  // レスポンス返却します
  show(res: express.Response): void {
    if (!this.validate()) {
      let errMsg = {'Error': 'You must specify name and age.'}
      res.send(JSON.stringify(errMsg))
    } else {
      res.send(JSON.stringify(this))
    }
  }
}

// express.Request を拡張してリクエストとして受け取るパラメータを再定義する
// 文字列または未定義のパラメータとして受け取る
interface UserProfileRequest extends express.Request {
  query: {
    name: string | undefined
    age: string | undefined
  }
}

// 受け取ったリクエストをそのままレスポンスとして返すルーティング
app.get('/', (req: UserProfileRequest, res: express.Response) => {
  let profile = new UserProfile(req.query.name, req.query.age)
  profile.show(res)
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

ポイント

UserProfileRequest インタフェースを定義して受け取るべきリクエストを定義しています
UserProfileRequest から UserProfile クラスのオブジェクトにシリアライズしていますが factory などを作って req から直接オブジェクトを生成してもいいかもしれません

クエリストリングは文字列でしか受け取れないので UserProfile.age も文字列で定義しています
本当は number として扱いたいので parseInt などを使ってどこかで変換してあげてもいいかもしれません

ちなみに undefined の部分はユニオンではなく Optional Property としても定義できます

interface UserProfileRequest extends express.Request {
  query: {
    name?: string
    age?: string
  }
}

あと toJSON の返り値の型も指定したかったので UserProfileType インタフェースを作成したあとで implements で UserProfile クラスを定義しています

最後に

今回は自力でシリアライズしましたが探せば便利なパッケージがあるかもしれません

0 件のコメント:

コメントを投稿