파일이 잘 올라갔지만, 이 파일을 볼 수 있어야합니다. 따라서 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
만들어지게 됩니다.
@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을 해놓을 파일을 등록하면, 그 폴더안에 넣은 모든 파일들은 외부에서 볼 수 있습니다.
{
"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_PATH
와 value
를 join
한다는 것입니다.
@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
지금까지 파일 업로드의 매우 클래식한 방법을 알아보았습니다. 다음 챕터에서는 현대에서 많이 사용되는 파일 업로드를 사용해 보겠습니다.