Skip to content

♻️ refactor: API Response, Request DTO 구현, ApiProperty 추가 #451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Aug 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
49c24ab
♻️ refactor: 컨트롤러 리팩토링 http 응답코드 추가
Jo-Minseok Aug 8, 2025
b118572
♻️ refactor: feed Service Feed Module exports에 추가
Jo-Minseok Aug 8, 2025
1035523
♻️ refactor: response DTO 적용 및 Request DTO 수정, Swagger 추가
Jo-Minseok Aug 9, 2025
844f995
✅ test: dto 수정에 따른 테스트 코드 수정
Jo-Minseok Aug 9, 2025
3716a28
♻️ refactor: response DTO 사용으로 변경
Jo-Minseok Aug 9, 2025
9db455d
♻️ refactor: response DTO 사용하도록 변경
Jo-Minseok Aug 9, 2025
19c81fb
Merge branch 'main' into refactor/api
Jo-Minseok Aug 9, 2025
a59aa2a
🧼 clean: 필요없는 멤버 변수 제거 및 스펠링 수정
Jo-Minseok Aug 9, 2025
59734dc
Merge branch 'main' into refactor/api
Jo-Minseok Aug 11, 2025
87ef839
♻️ refactor: dto example 추가
Jo-Minseok Aug 11, 2025
ef1b9c3
✨ feat: 파일 추가 API DTO 디렉토리 위치 수정 및 example 추가
Jo-Minseok Aug 11, 2025
8895c4b
✨ feat: 파일 삭제 API DTO 추가
Jo-Minseok Aug 11, 2025
358287a
♻️ refactor: 파일 추가 API Response DTO 사용, ApiResponse 사용하도록 변경
Jo-Minseok Aug 11, 2025
fa71d6a
🧼 clean: http code 추가
Jo-Minseok Aug 11, 2025
3eb7607
♻️ refactor: 댓글 업데이트 find 2번 수행 -\> 1번 수행 변경
Jo-Minseok Aug 11, 2025
09054d0
🐛 fix: 테스트 응답 문자열 변경
Jo-Minseok Aug 11, 2025
b832ccc
🐛 fix: docker init 데이터와 동일하게 수정
Jo-Minseok Aug 19, 2025
548aa28
Merge branch 'main' into refactor/api
Jo-Minseok Aug 19, 2025
d0f76d8
🐛 fix: validate 추가 및 멘트 수정
Jo-Minseok Aug 21, 2025
8b579c1
🐛 fix: 멘트 수정
Jo-Minseok Aug 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions server/src/activity/controller/activity.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Controller, Get, Param, Query } from '@nestjs/common';
import {
Controller,
Get,
HttpCode,
HttpStatus,
Param,
Query,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';

import { ActivityService } from '../service/activity.service';
import { ApiResponse } from '../../common/response/common.response';
import { ActivityParamRequestDto } from '../dto/request/activity-param.dto';
Expand All @@ -14,6 +20,7 @@ export class ActivityController {

@ApiReadActivities()
@Get(':userId')
@HttpCode(HttpStatus.OK)
async readActivities(
@Param() paramDto: ActivityParamRequestDto,
@Query() queryDto: ActivityQueryRequestDto,
Expand Down
2 changes: 1 addition & 1 deletion server/src/activity/dto/request/activity-param.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class ActivityParamRequestDto {
@IsInt({
message: '정수를 입력해주세요.',
})
@Min(1, { message: '사용자 ID는 1보다 커야합니다.' })
@Min(1, { message: '사용자 ID는 1 이상이어야 합니다.' })
@Type(() => Number)
userId: number;

Expand Down
21 changes: 11 additions & 10 deletions server/src/activity/dto/response/activity-read.dto.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { User } from '../../../user/entity/user.entity';

export class DailyActivityDto {
@ApiProperty({
example: '2024-01-15',
description: '활동 날짜 (YYYY-MM-DD)',
})
date: string;

@ApiProperty({
example: 5,
description: '해당 날짜의 조회수',
})
viewCount: number;

constructor(partial: Partial<DailyActivityDto>) {
Expand Down Expand Up @@ -43,7 +35,16 @@ export class ActivityReadResponseDto {
})
totalViews: number;

constructor(partial: Partial<ActivityReadResponseDto>) {
private constructor(partial: Partial<ActivityReadResponseDto>) {
Object.assign(this, partial);
}

static toResponseDto(dailyActivities: DailyActivityDto[], user: User) {
return new ActivityReadResponseDto({
dailyActivities: dailyActivities,
maxStreak: user.maxStreak,
currentStreak: user.currentStreak,
totalViews: user.totalViews,
});
}
}
18 changes: 5 additions & 13 deletions server/src/activity/service/activity.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ActivityRepository } from '../repository/activity.repository';
import { UserRepository } from '../../user/repository/user.repository';
import {
ActivityReadResponseDto,
DailyActivityDto,
} from '../dto/response/activity-read.dto';
import { UserService } from '../../user/service/user.service';

@Injectable()
export class ActivityService {
constructor(
private readonly activityRepository: ActivityRepository,
private readonly userRepository: UserRepository,
private readonly userService: UserService,
) {}

async readActivities(
userId: number,
year: number,
): Promise<ActivityReadResponseDto> {
const user = await this.userRepository.findOneBy({ id: userId });
if (!user) {
throw new NotFoundException('존재하지 않는 사용자입니다.');
}
const user = await this.userService.getUser(userId);

const activities =
await this.activityRepository.findActivitiesByUserIdAndYear(userId, year);
Expand All @@ -33,12 +30,7 @@ export class ActivityService {
}),
);

return new ActivityReadResponseDto({
dailyActivities,
maxStreak: user.maxStreak,
currentStreak: user.currentStreak,
totalViews: user.totalViews,
});
return ActivityReadResponseDto.toResponseDto(dailyActivities, user);
}

async upsertActivity(userId: number) {
Expand Down
1 change: 1 addition & 0 deletions server/src/admin/controller/admin.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class AdminController {
@ApiCreateAdmin()
@UseGuards(AdminAuthGuard)
@Post('/register')
@HttpCode(HttpStatus.CREATED)
async createAdmin(@Body() registerAdminBodyDto: RegisterAdminRequestDto) {
await this.adminService.createAdmin(registerAdminBodyDto);
return ApiResponse.responseWithNoContent(
Expand Down
2 changes: 0 additions & 2 deletions server/src/chat/service/chat.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ const CHAT_HISTORY_LIMIT = 20;

@Injectable()
export class ChatService {
private dayInit: boolean = false;

constructor(private readonly redisService: RedisService) {}

isMaxClientExceeded(userCount: number) {
Expand Down
6 changes: 3 additions & 3 deletions server/src/comment/dto/request/create-comment.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsNotEmpty, IsString } from 'class-validator';
import { IsInt, IsNotEmpty, IsString, Min } from 'class-validator';

export class CreateCommentRequestDto {
@ApiProperty({
Expand All @@ -13,13 +13,13 @@ export class CreateCommentRequestDto {
comment: string;

@ApiProperty({
example: '1',
example: 1,
description: '게시글 번호를 입력해주세요.',
})
@IsInt({
message: '숫자로 입력해주세요.',
})
@IsNotEmpty({ message: '피드 아이디를 입력하세요.' })
@Min(1, { message: '게시글 ID는 1 이상이어야 합니다.' })
feedId: number;

constructor(partial: Partial<CreateCommentRequestDto>) {
Expand Down
6 changes: 3 additions & 3 deletions server/src/comment/dto/request/delete-comment.dto.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsNotEmpty } from 'class-validator';
import { IsInt, Min } from 'class-validator';

export class DeleteCommentRequestDto {
@ApiProperty({
example: '1',
example: 1,
description: '댓글 번호를 입력해주세요.',
})
@IsInt({
message: '숫자로 입력해주세요.',
})
@IsNotEmpty({ message: '댓글 아이디를 입력하세요.' })
@Min(1, { message: '댓글 ID는 1 이상이어야 합니다.' })
commentId: number;

constructor(partial: Partial<DeleteCommentRequestDto>) {
Expand Down
5 changes: 3 additions & 2 deletions server/src/comment/dto/request/get-comment.dto.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsInt } from 'class-validator';
import { IsInt, Min } from 'class-validator';

export class GetCommentRequestDto {
@ApiProperty({
example: '게시글 ID',
example: 1,
description: '게시글 ID를 입력해주세요',
})
@IsInt({
message: '숫자로 입력해주세요.',
})
@Type(() => Number)
@Min(1, { message: '댓글 ID는 1 이상이어야 합니다.' })
feedId: number;

constructor(partial: Partial<GetCommentRequestDto>) {
Expand Down
6 changes: 3 additions & 3 deletions server/src/comment/dto/request/update-comment.dto.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsNotEmpty, IsString } from 'class-validator';
import { IsInt, IsNotEmpty, IsString, Min } from 'class-validator';

export class UpdateCommentRequestDto {
@ApiProperty({
example: '댓글 번호',
example: 1,
description: '댓글 번호를 입력해주세요.',
})
@IsInt({
message: '정수로 입력하세요.',
})
@IsNotEmpty({ message: '댓글 아이디를 입력하세요.' })
@Min(1, { message: '댓글 ID는 1 이상이어야 합니다.' })
commentId: number;

@ApiProperty({
Expand Down
57 changes: 57 additions & 0 deletions server/src/comment/dto/response/get-comment.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { ApiProperty } from '@nestjs/swagger';
import { Comment } from '../../entity/comment.entity';

export class GetCommentResponseDto {
@ApiProperty({
example: 1,
description: '댓글 ID',
})
id: number;

@ApiProperty({
example: 'example content',
description: '댓글 내용',
})
comment: string;

@ApiProperty({
example: '2025-01-01T00:00:00.000Z',
description: '댓글 작성 날짜',
})
date: Date;

@ApiProperty({
example: {
id: 1,
userName: 'example',
profileImage: 'https://example.com',
},
description: '댓글 작성자 정보',
})
user: {
id: number;
userName: string;
profileImage: string;
};

private constructor(partial: Partial<GetCommentResponseDto>) {
Object.assign(this, partial);
}

static toResponseDto(comment: Comment) {
new GetCommentResponseDto({
id: comment.id,
comment: comment.comment,
date: comment.date,
user: {
id: comment.user.id,
userName: comment.user.userName,
profileImage: comment.user.profileImage,
},
});
}

static toResponseDtoArray(comments: Comment[]) {
return comments.map(this.toResponseDto);
}
}
46 changes: 9 additions & 37 deletions server/src/comment/service/comment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@ import {
} from '@nestjs/common';
import { CommentRepository } from '../repository/comment.repository';
import { CreateCommentRequestDto } from '../dto/request/create-comment.dto';
import { FeedRepository } from '../../feed/repository/feed.repository';
import { UserRepository } from '../../user/repository/user.repository';
import { Payload } from '../../common/guard/jwt.guard';
import { DeleteCommentRequestDto } from '../dto/request/delete-comment.dto';
import { UpdateCommentRequestDto } from '../dto/request/update-comment.dto';
import { GetCommentRequestDto } from '../dto/request/get-comment.dto';
import { DataSource } from 'typeorm';
import { Comment } from '../entity/comment.entity';
import { GetCommentResponseDto } from '../dto/response/get-comment.dto';
import { FeedService } from '../../feed/service/feed.service';
import { UserService } from '../../user/service/user.service';

@Injectable()
export class CommentService {
constructor(
private readonly commentRepository: CommentRepository,
private readonly feedRepository: FeedRepository,
private readonly userRepository: UserRepository,
private readonly dataSource: DataSource,
private readonly userService: UserService,
private readonly feedService: FeedService,
) {}

private async getValidatedComment(
Expand All @@ -46,27 +47,12 @@ export class CommentService {
}

async get(commentDto: GetCommentRequestDto) {
const feed = await this.feedRepository.findOneBy({
id: commentDto.feedId,
});

if (!feed) {
throw new NotFoundException('게시글을 찾을 수 없습니다.');
}
await this.feedService.getFeed(commentDto.feedId);

const comments = await this.commentRepository.getCommentInformation(
commentDto.feedId,
);
return comments.map((row) => ({
id: row.id,
comment: row.comment,
date: row.date,
user: {
id: row.user.id,
userName: row.user.userName,
profileImage: row.user.profileImage,
},
}));
return GetCommentResponseDto.toResponseDtoArray(comments);
}

async create(userInformation: Payload, commentDto: CreateCommentRequestDto) {
Expand All @@ -75,21 +61,8 @@ export class CommentService {
await queryRunner.startTransaction();

try {
const feed = await this.feedRepository.findOneBy({
id: commentDto.feedId,
});
if (!feed) {
throw new NotFoundException('존재하지 않는 게시글입니다.');
}

const user = await this.userRepository.findOneBy({
id: userInformation.id,
});

if (!user) {
throw new NotFoundException('존재하지 않는 유저입니다.');
}

const feed = await this.feedService.getFeed(commentDto.feedId);
await this.userService.getUser(userInformation.id);
feed.commentCount++;
await queryRunner.manager.save(feed);
await queryRunner.manager.save(Comment, {
Expand Down Expand Up @@ -137,7 +110,6 @@ export class CommentService {
userInformation,
commentDto.commentId,
);

commentObj.comment = commentDto.newComment;
await this.commentRepository.save(commentObj);
}
Expand Down
2 changes: 1 addition & 1 deletion server/src/feed/controller/feed.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class FeedController {
) {}

@ApiReadFeedPagination()
@Get('')
@Get()
@HttpCode(HttpStatus.OK)
async readFeedPagination(
@Query() feedPaginationQueryDto: FeedPaginationRequestDto,
Expand Down
4 changes: 2 additions & 2 deletions server/src/feed/dto/request/feed-check.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { IsInt, Min } from 'class-validator';
export class FeedDeleteCheckDto {
@ApiProperty({
example: 1,
description: '조회할 ID 입력',
description: '조회할 게시글 ID 입력',
})
@IsInt({
message: '정수를 입력해주세요.',
})
@Min(1, { message: '조회하고자 하는 피드 ID는 1보다 커야합니다.' })
@Min(1, { message: '게시글 ID는 1 이상이어야 합니다.' })
@Type(() => Number)
feedId: number;

Expand Down
4 changes: 2 additions & 2 deletions server/src/feed/dto/request/feed-detail.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { IsInt, Min } from 'class-validator';
export class FeedDetailRequestDto {
@ApiProperty({
example: 1,
description: '조회할 ID 입력',
description: '조회할 게시글 ID 입력',
})
@IsInt({
message: '정수를 입력해주세요.',
})
@Min(1, { message: '조회하고자 하는 피드 ID는 1보다 커야합니다.' })
@Min(1, { message: '게시글 ID는 1 이상이어야 합니다.' })
@Type(() => Number)
feedId: number;

Expand Down
Loading