Skip to content
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

♻️ refactor: Response DTO 적용, request/response 분리 #9

Merged
merged 9 commits into from
Jan 9, 2025
11 changes: 5 additions & 6 deletions server/src/admin/controller/admin.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import {
} from '@nestjs/common';
import { Request, Response } from 'express';
import { AdminService } from '../service/admin.service';
import { RegisterAdminDto } from '../dto/register-admin.dto';
import { RegisterAdminRequestDto } from '../dto/request/register-admin.dto';
import { ApiTags } from '@nestjs/swagger';
import { ApiResponse } from '../../common/response/common.response';
import { LoginAdminDto } from '../dto/login-admin.dto';
import { LoginAdminRequestDto } from '../dto/request/login-admin.dto';
import { CookieAuthGuard } from '../../common/guard/auth.guard';
import { ApiLoginAdmin } from '../api-docs/loginAdmin.api-docs';
import { ApiReadSessionIdAdmin } from '../api-docs/readSessionIdAdmin.api-docs';
Expand All @@ -33,7 +33,7 @@ export class AdminController {
@HttpCode(HttpStatus.OK)
@UsePipes(ValidationPipe)
async loginAdmin(
@Body() loginAdminDto: LoginAdminDto,
@Body() loginAdminDto: LoginAdminRequestDto,
@Res({ passthrough: true }) response: Response,
@Req() request: Request,
) {
Expand All @@ -49,8 +49,7 @@ export class AdminController {
@Post('/logout')
async logoutAdmin(
@Req() request: Request,
@Res({ passthrough: true })
response: Response,
@Res({ passthrough: true }) response: Response,
) {
await this.adminService.logoutAdmin(request, response);
return ApiResponse.responseWithNoContent(
Expand All @@ -62,7 +61,7 @@ export class AdminController {
@UseGuards(CookieAuthGuard)
@Post('/register')
@UsePipes(ValidationPipe)
async createAdmin(@Body() registerAdminDto: RegisterAdminDto) {
async createAdmin(@Body() registerAdminDto: RegisterAdminRequestDto) {
await this.adminService.createAdmin(registerAdminDto);
return ApiResponse.responseWithNoContent(
'성공적으로 관리자 계정이 생성되었습니다.',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class LoginAdminDto {
export class LoginAdminRequestDto {
@ApiProperty({
example: 'minseokjo',
description: '관리자 로그인 아이디를 입력해주세요.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ApiProperty } from '@nestjs/swagger';

const PASSWORD_REG = /^(?=.*[!@#$%^&*()_+])[A-Za-z0-9!@#$%^&*()_+]+$/;

export class RegisterAdminDto {
export class RegisterAdminRequestDto {
@ApiProperty({
example: 'minseokjo',
description: '관리자 로그인 아이디를 입력해주세요.',
Expand Down
4 changes: 2 additions & 2 deletions server/src/admin/repository/admin.repository.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { Admin } from '../entity/admin.entity';
import { RegisterAdminDto } from '../dto/register-admin.dto';
import { RegisterAdminRequestDto } from '../dto/request/register-admin.dto';

@Injectable()
export class AdminRepository extends Repository<Admin> {
constructor(private dataSource: DataSource) {
super(Admin, dataSource.createEntityManager());
}

async createAdmin(registerAdminDto: RegisterAdminDto) {
async createAdmin(registerAdminDto: RegisterAdminRequestDto) {
const { loginId, password } = registerAdminDto;
const admin = this.create({
loginId,
Expand Down
8 changes: 4 additions & 4 deletions server/src/admin/service/admin.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import {
UnauthorizedException,
} from '@nestjs/common';
import { Response, Request } from 'express';
import { RegisterAdminDto } from '../dto/register-admin.dto';
import { RegisterAdminRequestDto } from '../dto/request/register-admin.dto';
import { AdminRepository } from '../repository/admin.repository';
import * as bcrypt from 'bcrypt';
import { cookieConfig } from '../../common/cookie/cookie.config';
import * as uuid from 'uuid';
import { RedisService } from '../../common/redis/redis.service';
import { LoginAdminDto } from '../dto/login-admin.dto';
import { LoginAdminRequestDto } from '../dto/request/login-admin.dto';

@Injectable()
export class AdminService {
Expand All @@ -23,7 +23,7 @@ export class AdminService {
) {}

async loginAdmin(
loginAdminDto: LoginAdminDto,
loginAdminDto: LoginAdminRequestDto,
response: Response,
request: Request,
) {
Expand Down Expand Up @@ -90,7 +90,7 @@ export class AdminService {
response.clearCookie('sessionId');
}

async createAdmin(registerAdminDto: RegisterAdminDto) {
async createAdmin(registerAdminDto: RegisterAdminRequestDto) {
let { loginId, password } = registerAdminDto;

const existingAdmin = await this.adminRepository.findOne({
Expand Down
2 changes: 1 addition & 1 deletion server/src/feed/api-docs/searchFeedList.api-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ApiOperation,
ApiQuery,
} from '@nestjs/swagger';
import { SearchType } from '../dto/search-feed.dto';
import { SearchType } from '../dto/request/search-feed.dto';

export function ApiSearchFeedList() {
return applyDecorators(
Expand Down
45 changes: 25 additions & 20 deletions server/src/feed/controller/feed.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
ValidationPipe,
} from '@nestjs/common';
import { FeedService } from '../service/feed.service';
import { QueryFeedDto } from '../dto/query-feed.dto';
import { SearchFeedReq } from '../dto/search-feed.dto';
import { FeedPaginationRequestDto } from '../dto/request/feed-pagination.dto';
import { SearchFeedRequestDto } from '../dto/request/search-feed.dto';
import { Response, Request } from 'express';
import { Observable } from 'rxjs';
import { EventEmitter2 } from '@nestjs/event-emitter';
Expand All @@ -25,7 +25,7 @@ import { ApiReadTrendFeedList } from '../api-docs/readTrendFeedList.api-docs';
import { ApiSearchFeedList } from '../api-docs/searchFeedList.api-docs';
import { ApiUpdateFeedViewCount } from '../api-docs/updateFeedViewCount.api-docs';
import { ApiReadRecentFeedList } from '../api-docs/readRecentFeedList.api-docs';
import { Feed } from '../entity/feed.entity';
import { FeedTrendResponseDto } from '../dto/response/feed-pagination.dto';

@ApiTags('Feed')
@Controller('feed')
Expand All @@ -43,7 +43,7 @@ export class FeedController {
transform: true,
}),
)
async readFeedPagination(@Query() queryFeedDto: QueryFeedDto) {
async readFeedPagination(@Query() queryFeedDto: FeedPaginationRequestDto) {
return ApiResponse.responseWithData(
'피드 조회 완료',
await this.feedService.readFeedPagination(queryFeedDto),
Expand All @@ -54,22 +54,27 @@ export class FeedController {
@Sse('trend/sse')
async readTrendFeedList() {
return new Observable((observer) => {
this.feedService.readTrendFeedList().then((trendData) => {
observer.next({
data: {
message: '현재 트렌드 피드 수신 완료',
data: trendData,
},
this.feedService
.readTrendFeedList()
.then((trendData: FeedTrendResponseDto[]) => {
observer.next({
data: {
message: '현재 트렌드 피드 수신 완료',
data: trendData,
},
});
});
});
this.eventService.on('ranking-update', (trendData: Feed[]) => {
observer.next({
data: {
message: '새로운 트렌드 피드 수신 완료',
data: trendData,
},
});
});
this.eventService.on(
'ranking-update',
(trendData: FeedTrendResponseDto[]) => {
observer.next({
data: {
message: '새로운 트렌드 피드 수신 완료',
data: trendData,
},
});
},
);
});
}

Expand All @@ -82,7 +87,7 @@ export class FeedController {
}),
new ValidationPipe(),
)
async searchFeedList(@Query() searchFeedReq: SearchFeedReq) {
async searchFeedList(@Query() searchFeedReq: SearchFeedRequestDto) {
const data = await this.feedService.searchFeedList(searchFeedReq);
return ApiResponse.responseWithData('검색 결과 조회 완료', data);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IsInt, IsOptional, Min } from 'class-validator';
import { Type } from 'class-transformer';

export class QueryFeedDto {
export class FeedPaginationRequestDto {
@IsOptional()
@Min(0, { message: 'lastId 값은 0 이상이어야 합니다.' })
@IsInt({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Feed } from '../../feed/entity/feed.entity';
import { IsDefined, IsEnum, IsInt, IsString, Min } from 'class-validator';
import { Type } from 'class-transformer';

Expand All @@ -8,7 +7,7 @@ export enum SearchType {
ALL = 'all',
}

export class SearchFeedReq {
export class SearchFeedRequestDto {
@IsDefined({
message: '검색어를 입력해주세요.',
})
Expand Down Expand Up @@ -37,38 +36,7 @@ export class SearchFeedReq {
@Type(() => Number)
limit?: number = 4;

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

export class SearchFeedResult {
constructor(
private id: number,
private blogName: string,
private title: string,
private path: string,
private createdAt: Date,
) {}

static feedsToResults(feeds: Feed[]): SearchFeedResult[] {
return feeds.map((item) => {
return new SearchFeedResult(
item.id,
item.blog.name,
item.title,
item.path,
item.createdAt,
);
});
}
}

export class SearchFeedRes {
constructor(
private totalCount: number,
private result: SearchFeedResult[],
private totalPages: number,
private limit: number,
) {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FeedView } from '../../feed/entity/feed.entity';
import { FeedView } from '../../entity/feed.entity';

export class FeedPaginationResponseDto {
export class FeedResult {
private constructor(
private id: number,
private author: string,
Expand All @@ -13,8 +13,8 @@ export class FeedPaginationResponseDto {
private isNew: boolean,
) {}

private static toFeedPaginationResponseDto(feed: FeedPaginationResult) {
return new FeedPaginationResponseDto(
private static toResultDto(feed: FeedPaginationResult) {
return new FeedResult(
feed.feedId,
feed.blogName,
feed.blogPlatform,
Expand All @@ -27,10 +27,20 @@ export class FeedPaginationResponseDto {
);
}

public static mapToPaginationResponseDtoArray(
FeedList: FeedPaginationResult[],
) {
return FeedList.map(this.toFeedPaginationResponseDto);
public static toResultDtoArray(feedList: FeedPaginationResult[]) {
return feedList.map(this.toResultDto);
}
}

export class FeedPaginationResponseDto {
private constructor(
private result: FeedResult[],
private lastId: number,
private hasMore: boolean,
) {}

static toResponseDto(result: FeedResult[], lastId: number, hasMore: boolean) {
return new FeedPaginationResponseDto(result, lastId, hasMore);
}
}

Expand All @@ -48,7 +58,7 @@ export class FeedTrendResponseDto {
private viewCount: number,
) {}

private static toFeedTrendResponseDto(feed: FeedView) {
private static toResponseDto(feed: FeedView) {
return new FeedTrendResponseDto(
feed.feedId,
feed.blogName,
Expand All @@ -61,7 +71,7 @@ export class FeedTrendResponseDto {
);
}

public static toFeedTrendResponseDtoArray(FeedList: FeedView[]) {
return FeedList.map(this.toFeedTrendResponseDto);
public static toResponseDtoArray(FeedList: FeedView[]) {
return FeedList.map(this.toResponseDto);
}
}
43 changes: 43 additions & 0 deletions server/src/feed/dto/response/recent.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export class FeedRecentResponseDto {
private constructor(
private id: number,
private author: string,
private blogPlatform: string,
private title: string,
private path: string,
private createdAt: string,
private thumbnail: string,
private viewCount: number,
private isNew: boolean,
) {}

static toResponseDto(feed: FeedRecentRedis) {
return new FeedRecentResponseDto(
feed.id,
feed.blogName,
feed.blogPlatform,
feed.title,
feed.path,
feed.createdAt,
feed.thumbnail,
feed.viewCount,
feed.isNew,
);
}

static toResponseDtoArray(feeds: FeedRecentRedis[]) {
return feeds.map(this.toResponseDto);
}
}

export type FeedRecentRedis = {
id: number;
blogPlatform: string;
createdAt: string;
viewCount: number;
blogName: string;
thumbnail: string;
path: string;
title: string;
isNew?: boolean;
};
Loading
Loading