Skip to content

Commit

Permalink
Merge pull request #109 from boostcampwm-2024/feature/api/stockList-#57
Browse files Browse the repository at this point in the history
[BE] 최근 검색어 저장 API 분리
  • Loading branch information
jinddings authored Nov 14, 2024
2 parents 8c644a8 + 6e73abe commit a897c8a
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 17 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,23 @@ jobs:
docker system prune -af
echo "${{ secrets.ENV }}" > .env
docker network create juga-network || true
docker run -d \
--name redis \
--network juga-network \
-p 6379:6379 \
-v redis_data:/data \
redis:latest redis-server --appendonly yes
docker pull ${{ env.DOCKER_IMAGE }}-${{ matrix.app.name }}:${{ env.DOCKER_TAG }}
docker stop ${{ matrix.app.container }} || true
docker rm ${{ matrix.app.container }} || true
docker run -d \
--name ${{ matrix.app.container }} \
--network juga-network \
-p ${{ matrix.app.port }}:${{ matrix.app.port }} \
--env-file .env \
-v /etc/localtime:/etc/localtime:ro \
-e TZ=Asia/Seoul \
${{ env.DOCKER_IMAGE }}-${{ matrix.app.name }}:${{ env.DOCKER_TAG }}
- name: Remove Github Action Ip to Security group
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/deply-alpha.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,21 @@ jobs:
docker system prune -af
echo "${{ secrets.ENV }}" > .env
docker network create juga-network || true
docker run -d \
--name redis \
--network juga-network \
-p 6379:6379 \
-v redis_data:/data \
redis:latest redis-server --appendonly yes
docker pull ${{ env.DOCKER_IMAGE }}-${{ matrix.app.name }}:${{ env.DOCKER_TAG }}
docker stop ${{ matrix.app.container }} || true
docker rm ${{ matrix.app.container }} || true
docker run -d \
--name ${{ matrix.app.container }} \
--network juga-network \
-p ${{ matrix.app.port }}:${{ matrix.app.port }} \
--env-file .env \
${{ env.DOCKER_IMAGE }}-${{ matrix.app.name }}:${{ env.DOCKER_TAG }}
Expand Down
27 changes: 27 additions & 0 deletions BE/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: '3'
services:
api:
build:
context: .
dockerfile: Dockerfile
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- REDIS_HOST=redis
- REDIS_PORT=6379
depends_on:
- redis
restart: unless-stopped

redis:
image: redis:latest
ports:
- '6379:6379'
volumes:
- redis_data:/data
command: redis-server --appendonly yes
restart: unless-stopped

volumes:
redis_data:
4 changes: 2 additions & 2 deletions BE/src/common/redis/redis.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { RedisDomainService } from './redis.domain-service';
provide: 'REDIS_CLIENT',
useFactory: () => {
return new Redis({
host: process.env.REDIS_HOST,
port: Number(process.env.REDIS_PORT),
host: process.env.REDIS_HOST || 'redis',
port: Number(process.env.REDIS_PORT || 6379),
});
},
},
Expand Down
2 changes: 1 addition & 1 deletion BE/src/stock/list/interface/search-params.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export interface SearchParams {
name?: string;
market?: string;
code?: string;
userId: number;
userId?: string;
}
51 changes: 46 additions & 5 deletions BE/src/stock/list/stock-list.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Controller, Get, Query, Req, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Controller, Get, Post, Query, Req, UseGuards } from '@nestjs/common';
import {
ApiBearerAuth,
ApiBody,
ApiOperation,
ApiQuery,
ApiResponse,
ApiTags,
} from '@nestjs/swagger';
import { Request } from 'express';
import { JwtAuthGuard } from 'src/auth/jwt-auth-guard';
import { StockListService } from './stock-list.service';
Expand Down Expand Up @@ -36,13 +43,11 @@ export class StockListController {
@Get('/search')
@UseGuards(JwtAuthGuard)
async searchWithQuery(
@Req() req: Request,
@Query('name') name?: string,
@Query('market') market?: string,
@Query('code') code?: string,
): Promise<StockListResponseDto[]> {
const userId = parseInt(req.user.userId, 10);
return this.stockListService.search({ name, market, code, userId });
return this.stockListService.search({ name, market, code });
}

@ApiOperation({
Expand All @@ -58,4 +63,40 @@ export class StockListController {
async findOne(@Query('code') code: string): Promise<StockListResponseDto> {
return this.stockListService.findOne(code);
}

@Post('/search/addHistory')
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary: '검색어 히스토리 추가 API',
description: '특정 유저의 검색어 히스토리를 추가한다.',
})
@ApiBody({
schema: {
type: 'object',
properties: {
searchTerm: { type: 'string' },
},
},
})
@ApiBearerAuth()
async addSearchHistory(@Req() req: Request) {
const { searchTerm } = req.body;
const userId = parseInt(req.user.userId, 10);
await this.stockListService.addSearchTermToRedis({
searchTerm,
userId,
});
}

@Get('/search/getHistory')
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary: '검색어 히스토리 조회 API',
description: '특정 유저의 검색어 히스토리를 조회한다.',
})
@ApiBearerAuth()
async getSearchHistory(@Req() req: Request) {
const userId = req.user.userId;
return this.stockListService.getSearchTermFromRedis(userId);
}
}
23 changes: 16 additions & 7 deletions BE/src/stock/list/stock-list.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,33 @@ export class StockListService {
}

async search(params: SearchParams): Promise<StockListResponseDto[]> {
await this.addSearchTermToRedis(params);
const stocks = await this.stockListRepository.search(params);
return stocks.map((stock) => this.toResponseDto(stock));
}

async addSearchTermToRedis(params: SearchParams) {
const key = `search:${params.userId}`;
async addSearchTermToRedis(searchInfo: {
userId: Number;
searchTerm: string;
}) {
const { userId, searchTerm } = searchInfo;
const key = `search:${userId}`;
const timeStamp = Date.now();

const { name, market, code } = params;

const searchTerm = name || market || code;

await this.redisDomainService.zadd(key, timeStamp, searchTerm);

const searchHistoryCount = await this.redisDomainService.zcard(key);
if (searchHistoryCount > this.SearchHistoryLimit) {
await this.redisDomainService.zremrangebyrank(key, 0, 0);
}
}

async getSearchTermFromRedis(userId: string): Promise<string[]> {
const key = `search:${userId}`;

return await this.redisDomainService.zrevrange(
key,
0,
this.SearchHistoryLimit - 1,
);
}
}

0 comments on commit a897c8a

Please sign in to comment.