1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NestJS で「Do not know how to serialize a BigInt」というエラーが発生した場合の対処法

Posted at

タイトル通り、NestJS で開発を進める中で生じた「Do not know how to serialize a BigInt」というエラーが生じた際の対処法についてメモ書き。

原因

[Nest] 4865 - 2023/03/19 19:06:06 ERROR [ExceptionsHandler] Do not know how to serialize a BigInt
TypeError: Do not know how to serialize a BigInt

直訳すると、「BigInt をシリアライズする方法を知りません」といった感じでしょうか...。

そもそもの仕様として、JSON においては BigInt のシリアライズに対応していないようです。

対処法

これに対するアプローチは色々と存在するようですが、NestJS でどう対処すれば良いのか調べてみました。

状況によっても異なるとは思いますが、今回は下記のようなケースを想定としています。

  • ユーザー一覧の情報を JSON 形式で取得できる /api/v1/users というエンドポイント
  • ユーザーの情報には BigInt 型のデータが含まれる

たとえば、こんな感じのコードがあるとして...

./src/controllers/users/users_controller.ts
import { Controller, Get } from '@nestjs/common';
import { IsString, IsInt, IsArray } from 'class-validator';

class UserDto {
  @IsInt()
  id: number;

  @IsInt()
  bigIntId: bigint;

  @IsString()
  name: string;

  constructor(partial: Partial<UserDto>) {
    Object.assign(this, partial)
  }
}

export class FindAllUserResponseDto {
  @IsArray()
  users: UserDto[]

  constructor(partial: Partial<FindAllUserResponseDto>) {
    Object.assign(this, partial)
  }
}

@Controller({ path: 'users', version: '1' })
export class UsersController {
  @Get('/users')

  async findAll() {
    const users = [
      { id: 1, bigIntId: BigInt(12345678901234), name: '山田 太郎' },
      { id: 2, bigIntId: BigInt(56789012345678), name: '鈴木 一郎' },
    ];

    return new FindAllUserResponseDto({
      users: users.map((user) => {
        return new UserDto({
          id: user.id,
          bigIntId: user.bigIntId,
          name: user.name,
        })
      })
    })
  }
}

このままだと先述のエラーが発生してしまいました。

エラーを解消するためには、以下のように修正します。

./src/controllers/users/users_controller.ts
import { Controller, Get, UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
import { IsString, IsInt, IsArray } from 'class-validator';
import { Transform } from 'class-transformer';

class UserDto {
  @IsInt()
  id: number;

  @IsInt()
  @Transform(({ value }) => value.toString()) // BigIntを文字列に変換する
  bigIntId: bigint;

  @IsString()
  name: string;

  constructor(partial: Partial<UserDto>) {
    Object.assign(this, partial)
  }
}

export class FindAllUserResponseDto {
  @IsArray()
  users: UserDto[]

  constructor(partial: Partial<FindAllUserResponseDto>) {
    Object.assign(this, partial)
  }
}

@Controller({ path: 'sites', version: '1' })
export class SitesController {
  @Get('/sites')
  @UseInterceptors(ClassSerializerInterceptor) // ClassSerializerInterceptor を使用する

  async findAll() {
    const users = [
      { id: 1, bigIntId: BigInt(12345678901234), name: '山田 太郎' },
      { id: 2, bigIntId: BigInt(56789012345678), name: '鈴木 一郎' },
    ];

    return new FindAllUserResponseDto({
      users: users.map((user) => {
        return new UserDto({
          id: user.id,
          bigIntId: user.bigIntId,
          name: user.name,
        })
      })
    })
  }
}
  • UserDto で @Transform デコレーターを使用して、BigInt の値を文字列に変換
  • ClassSerializerInterceptor を使用して、UserDto をシリアル化

このように、NestJS では ClassSerializerInterceptor と @Transform デコレーターの組み合わせで BigInt をシリアライズすることができました。

[
	{
		"id": "1",
		"bigIntId": "12345678901234",
		"name": "山田 太郎"
	},
	{
		"id": 2,
		"bigIntId": "56789012345678",
		"name": "鈴木 一郎"
	}
]
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?