통계 검색/업데이트 로직
현재 소환사 통계 검색/새로고침은 여러 Riot API를 통해 값을 가져옵니다.
- 소환사의 개인 정보(summonerId, puuid, …)를 소환사 이름으로 가져옵니다.
- 소환사의 ID로 소환사의 기록(Gain, Tier, Level, Lp…)을 가져옵니다.
- 소환사의 summmonerId로 소환사의 가장 위대한 챔피언을 얻으십시오.
- 소환사의 Puuid와 플레이한 매치 ID인 MatchId 10개를 가져옵니다.
- 소환사의 matchId로 자세한 게임 내 데이터를 가져옵니다.
여기서 숫자 4가 10이 되면 게임 데이터가 루프됩니다.
그 결과 Riot API에 서머너 검색/업데이트 요청이 약 14회 정도 이루어집니다.
그리고 Riot에는 API 요청에 대한 제한이 있으며 제한이 설정되면 1~2분 동안 Riot API를 사용할 수 없습니다.
따라서 소환사 기록이 업데이트되면 소환사에게 5분 간격을 설정하여 과도한 API 요청을 방지하는 것이 목적입니다.
해결하다
NestJ에서는 컨트롤러가 인터셉터의 HTTP 요청 처리를 수행하기 전/후에 요청 값을 변경할 수 있습니다.
따라서 인터셉터는 전체 새로 고침 요청 매개 변수 값을 먼저 필터링하는 논리를 구현합니다.
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class ThrottleInterceptor implements NestInterceptor {
private readonly cache = new Map<string, number>();
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const summonerName = request.params.summonerName;
const requestTime = Date.now();
if (this.cache.has(summonerName)) {
const lastRequestTime = this.cache.get(summonerName);
if (requestTime - lastRequestTime < 5 * 60 * 1000) {
throw new HttpException('Too many requests', HttpStatus.TOO_MANY_REQUESTS);
}
}
this.cache.set(summonerName, requestTime);
return next.handle();
}
}
인터셉터의 필드는 카드 데이터 구조로 키(소환사 이름)와 값(요청 시간)이라고 합니다.
그리고 요청이 오면 해당 필드에서 소환사를 찾아주고, 요청 시간이 5분 미만이면 429 오류를 내뱉는다.
시험
it("/GET 소환사 전적 갱신 특정 소환사 갱신 후 해당 소환사 5분 안에 다시 요청시 error?", async () => {
const summonerName = encodeURIComponent("쿠바버샷추가");
await request(app.getHttpServer()).get(`/summoner/refresh/${summonerName}`);
const response = await request(app.getHttpServer()).get(
`/summoner/refresh/${summonerName}`
);
expect(response.statusCode).toBe(429);
expect(response.body.message).toEqual("Too many requests");
});

동일한 소환사를 두 번 업데이트하면 일반적으로 429 코드와 오류 메시지가 나타납니다.
e2e 테스트를 통해 확실하게 API를 확인할 수 있습니다.
