서버/nodejs

[nestjs] 스웨거 사용시 주의사항 - 순환참조 에러

멍개. 2022. 8. 29. 07:50

nestjs에서 스웨거 사용시 주의사항을 살펴보겠습니다.

스웨거를 사용하다보면 다음과 같은 에러가 발생할 수 있습니다.

/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:170
            throw new Error(`A circular dependency has been detected (property key: "${key}"). Please, make sure that each side of a bidirectional relationships are using lazy resolvers ("type: () => ClassType").`);
                  ^
Error: A circular dependency has been detected (property key: "user"). Please, make sure that each side of a bidirectional relationships are using lazy resolvers ("type: () => ClassType").
    at SchemaObjectFactory.createNotBuiltInTypeReference (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:170:19)
    at SchemaObjectFactory.createSchemaMetadata (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:280:25)
    at SchemaObjectFactory.mergePropertyWithMetadata (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:122:21)
    at /Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:79:35
    at Array.map (<anonymous>)
    at SchemaObjectFactory.extractPropertiesFromType (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:78:52)
    at SchemaObjectFactory.createQueryOrParamSchema (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:57:45)
    at /Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:31:29
    at Array.map (<anonymous>)
    at SchemaObjectFactory.createFromModel (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:20:45)

해당 에러가 발생하는 케이스를 만들어보겠습니다.

예를 들어서 유저와 게시글 관계를 정의할 때 다음과 같이 데이터를 모델링합니다.

▶ 유저 DTO

import { ApiProperty } from "@nestjs/swagger";

import { PostDto } from "./post.dto";

export class UserDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  name: string;

  @ApiProperty({ type : [PostDto] })
  posts: [PostDto];
}

유저는 다수의 게시글을 가질 수 있습니다.

▶ 게시글 DTO

 
import { ApiProperty } from "@nestjs/swagger";

import { UserDto } from "./user.dto";

export class PostDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  title: string;

  @ApiProperty({ type : UserDto })
  user: UserDto;
}

하나의 게시글은 하나의 유저를 가집니다.

이때 user와 post는 서로 순환참조 관계를 가집니다.

· 해결방법

스웨거의 ApiProperty는 이런 순환참조를 대비하여 lazy loading을 이용하합니다. 바로 @ApiProperty는 type을 전달할 때 함수의 반환값을 이용합니다.

▶ 유저 DTO

import { ApiProperty } from "@nestjs/swagger";

import { PostDto } from "./post.dto";

export class UserDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  name: string;

  @ApiProperty({ type : () => [PostDto] })
  posts: [PostDto];
}

▶ 게시글 DTO

import { ApiProperty } from "@nestjs/swagger";

import { UserDto } from "./user.dto";

export class PostDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  title: string;

  @ApiProperty({ type : () => UserDto })
  user: UserDto;
}

함수의 반환값으로 타입을 전달하면 lazy loading이 되기 때문에 스웨거 로드가 정상적으로 이루어집니다.