APIからのレスポンスを動的にチェックする方法
動的にレスポンスの構造をチェックしたい
TypeScriptによって静的な型チェックを行うことはできるが、APIからのレスポンスなどの動的なチェックを行いたい。
レスポンスのバリデーション用の構造とTypeScriptの型を一元管理したい。
io-tsを使用する
io-tsというライブラリーで可能。
https://github.com/gcanti/io-ts
手順
io-tsでAPIからのレスポンスの構造を定義する
const HogeResValidator = t.type({
id: t.number,
name: t.string,
age: t.number,
description: t.union([t.string, t.null]),
})
上記の例では idはnumber, nameはstring, ageはnumber, descriptionはstring | null となっている。
optionalなプロパティーを定義する場合は、t.partialを利用する。
https://github.com/gcanti/io-ts#mixing-required-and-optional-props
TypeScriptの型を生成する
上記の構造からTypeScript用の型を生成する。
type HogeResType = t.TypeOf<typeof HogeResValidator>
APIコールにレスポンスの型とバリデーション処理を追加する
今回はaxiosを使った例。
axios.get<HogeResType>('/user')
.then(res => {
const v = HogeResValidator.decode(res.data)
if(isLeft(v)) throw new Error('failed to validate response')
// バリデーション成功時の処理
})
.catch(err => {
// エラー処理
})
PathReporter.report を使用することで、バリデーションエラー時にどこがNGだったかを取得することができるので便利。
https://github.com/gcanti/io-ts#error-reporters
全体のコード
const HogeResValidator = t.type({
id: t.number,
name: t.string,
age: t.number,
description: t.union([t.string, t.null]),
})
type HogeResType = t.TypeOf<typeof HogeResValidator>
axios.get<HogeResType>('/user')
.then(res => {
const v = HogeResValidator.decode(res.data)
if(isLeft(v)) throw new Error('failed to validate response')
// バリデーション成功時の処理
})
.catch(err => {
// エラー処理
})
レスポンスの構造とそれから作成された型(HogeResValidatorとHogeResType)は別ファイルで管理すると良い。
感想
バリデーション用のデータ構造からTypeScriptの型を生成できるので、一元管理できるので便利。
もし、データ構造が変わった場合は、HogeResValidator(バリデーション用の構造)を変更することでHogeResType(TypeScriptの型)も自動で変更される。
API側で変更が入ってレスポンスの構造が変わった時に、レスポンス取得時のバリデーションで検知できるので、バグを見つけやすくなる。
ディスカッション
コメント一覧
まだ、コメントがありません