NestJS-Static File Serving

jaegeunsong97·2024년 2월 6일
0

NestJS

목록 보기
25/37
post-custom-banner

🖊️Static File Serving 옵션 추가

파일이 잘 올라갔지만, 이 파일을 볼 수 있어야합니다. 따라서 Static File을 이용해서 볼 수 있도록 만들겠습니다. Static File은 이미지를 의미합니다. 이후에 경로를 외부에서도 볼 수 있도록 바꾸는 것입니다. nest.js에서는 이렇게 이미지와 같은 Static File들을 외부에서도 볼 수 있도록 기능을 만들어 놓았습니다. 먼저 패키지를 설치합니다.

yarn add @nestjs/serve-static

app.module.ts에 ServeStaticModule를 추가합니다. rootPath는 파일들을 serving할 최상단의 폴더를 의미합니다. 즉 public을 포함하는 것입니다.

따라서 PUBLIC_FOLDER_PATH를 하게되면 public은 건너뛰고 /posts/4022.jpg이렇게 주소가 만들어집니다. 하지만 이미 우리는 posts 컨트롤러에 해당 URL이 존재하기 때문에 약간의 변경을 주겠습니다.

serveRoot/public을 주므로써 /public/posts/4022.jpg만들어지게 됩니다.

  • app.module.ts
@Module({
    imports: [
        ConfigModule.forRoot({
            envFilePath: '.env',
            isGlobal: true,
        }),
        TypeOrmModule.forRoot({
            type: 'postgres',
            host: process.env[ENV_DB_HOST_KEY],
            port: parseInt(process.env[ENV_DB_PORT_KEY]),
            username: process.env[ENV_DB_USERNAME_KEY],
            password: process.env[ENV_DB_PASSWORD_KEY],
            database: process.env[ENV_DB_DATABASE_KEY],
            entities: [
                PostsModel,
                UsersModel,
            ],
            synchronize: true,
        }),
        PostsModule,
        UsersModule,
        AuthModule,
        CommonModule,
      	// 추가
        ServeStaticModule.forRoot({
            // 4022.jpg      
            rootPath: PUBLIC_FOLDER_PATH, // http://localhost:3000/posts/4022.jpg
            serveRoot: '/public' // http://localhost:3000/public/posts/4022.jpg
        }),
      	// 여기까지
    ],
    controllers: [AppController],
    providers: [AppService, {
        provide: APP_INTERCEPTOR,
        useClass: ClassSerializerInterceptor,
    }],
})
export class AppModule {}

포스트맨으로 잘 나오는지 테스트를 하겠습니다.

{
    "data": [
        {
            "id": 109,
            "updatedAt": "2024-02-04T04:30:17.814Z",
            "createdAt": "2024-02-04T04:30:17.814Z",
            "title": "파일 업로드",
            "content": "파일 업로드 테스트",
            "image": "06961c7a-b923-4d24-a13b-d4cc2fa5ee63.png",
            "likeCount": 0,
            "commentCount": 0,
            "author": {
                "id": 1,
                "updatedAt": "2024-01-26T05:58:10.800Z",
                "createdAt": "2024-01-26T05:58:10.800Z",
                "nickname": "codefactory",
                "email": "codefactory@codefactory.ai",
                "role": "USER"
            }
        },
        .
        .
        {
            "id": 90,
            "updatedAt": "2024-01-28T02:12:54.437Z",
            "createdAt": "2024-01-28T02:12:54.437Z",
            "title": "임의로 생성된 81",
            "content": "임의로 생성된 포수트 내용 81",
            "image": null,
            "likeCount": 0,
            "commentCount": 0,
            "author": {
                "id": 1,
                "updatedAt": "2024-01-26T05:58:10.800Z",
                "createdAt": "2024-01-26T05:58:10.800Z",
                "nickname": "codefactory",
                "email": "codefactory@codefactory.ai",
                "role": "USER"
            }
        }
    ],
    "cursor": {
        "after": 90
    },
    "count": 20,
    "next": "http://localhost:3000/posts?order__createdAt=DESC&take=20&where__id__less_than=90"
}

image를 복사해서 URL에 넣어봅니다.

http://localhost:3000/public/posts/06961c7a-b923-4d24-a13b-d4cc2fa5ee63.png

StaticFile Serving을 해놓을 파일을 등록하면, 그 폴더안에 넣은 모든 파일들은 외부에서 볼 수 있습니다.


🖊️Class Transformer 이용해서 URL에 prefix 추가

{
            "id": 109,
            "updatedAt": "2024-02-04T04:30:17.814Z",
            "createdAt": "2024-02-04T04:30:17.814Z",
            "title": "파일 업로드",
            "content": "파일 업로드 테스트",
            "image": "06961c7a-b923-4d24-a13b-d4cc2fa5ee63.png",
            "likeCount": 0,
            "commentCount": 0,
            "author": {
                "id": 1,
                "updatedAt": "2024-01-26T05:58:10.800Z",
                "createdAt": "2024-01-26T05:58:10.800Z",
                "nickname": "codefactory",
                "email": "codefactory@codefactory.ai",
                "role": "USER"
            }
        },

image에서 prefix까지 전부 받으면 좋을 것 같습니다. /public/posts까지 붙여서 말이죠.

엔티티에서 프로퍼티를 변경할 수 있는 기능은 class-transformer를 사용하는 것입니다. 이번에는 @Transform()을 배워보도록 하겠습니다.

@Transform 내부에서 value를 받습니다. 이 값은 image 키값에 매칭이되는 value를 의미합니다. 예를 들면 4022.jpg를 의미합니다.

따라서 이 값이 존재하는 경우에만 POST_PUBLIC_IMAGE_PATHvaluejoin한다는 것입니다.

  • posts.entity.ts
@Entity()
export class PostsModel extends BaseModel {

    @ManyToOne(() => UsersModel, (user) => user.posts, {
      	nullable: false,
    })
    author: UsersModel;

    @Column()
    @IsString({
      	message: stringValidationMessage
    }) 
    title: string;

    @Column()
    @IsString({
      	message: stringValidationMessage
    }) 
    content: string;

    @Column({
      	nullable: true,
    })
    // value가 존재할 경우에만 value 앞에 /public/posts를 붙임, value가 존재하지 않으면 null or undefined
    @Transform(({value}) => value && `/${join(POST_PUBLIC_IMAGE_PATH, value)}`) // value: image에 입력된 값 의미
    image?: string;

    @Column()
    likeCount: number;

    @Column()
    commentCount: number;
}

포스트맨으로 테스트를 하겠습니다.

{
    "data": [
        {
            "id": 109,
            "updatedAt": "2024-02-04T04:30:17.814Z",
            "createdAt": "2024-02-04T04:30:17.814Z",
            "title": "파일 업로드",
            "content": "파일 업로드 테스트",
            "image": "/public\\posts\\06961c7a-b923-4d24-a13b-d4cc2fa5ee63.png",
            "likeCount": 0,
            "commentCount": 0,
            "author": {
                "id": 1,
                "updatedAt": "2024-01-26T05:58:10.800Z",
                "createdAt": "2024-01-26T05:58:10.800Z",
                "nickname": "codefactory",
                "email": "codefactory@codefactory.ai",
                "role": "USER"
            }
        },
        .
        .
        {
            "id": 90,
            "updatedAt": "2024-01-28T02:12:54.437Z",
            "createdAt": "2024-01-28T02:12:54.437Z",
            "title": "임의로 생성된 81",
            "content": "임의로 생성된 포수트 내용 81",
            "image": null,
            "likeCount": 0,
            "commentCount": 0,
            "author": {
                "id": 1,
                "updatedAt": "2024-01-26T05:58:10.800Z",
                "createdAt": "2024-01-26T05:58:10.800Z",
                "nickname": "codefactory",
                "email": "codefactory@codefactory.ai",
                "role": "USER"
            }
        }
    ],
    "cursor": {
        "after": 90
    },
    "count": 20,
    "next": "http://localhost:3000/posts?order__createdAt=DESC&take=20&where__id__less_than=90"
}
http://localhost:3000/public//posts//06961c7a-b923-4d24-a13b-d4cc2fa5ee63.png

지금까지 파일 업로드의 매우 클래식한 방법을 알아보았습니다. 다음 챕터에서는 현대에서 많이 사용되는 파일 업로드를 사용해 보겠습니다.

profile
블로그 이전 : https://medium.com/@jaegeunsong97
post-custom-banner

0개의 댓글