Skip to content

Comments

[REFACTOR] recent-summary 연도 fallback 및 미존재 엔드포인트 404 처리#428

Open
TAEW00KIM wants to merge 3 commits intomainfrom
refactor/recent-summary-latest-year-404
Open

[REFACTOR] recent-summary 연도 fallback 및 미존재 엔드포인트 404 처리#428
TAEW00KIM wants to merge 3 commits intomainfrom
refactor/recent-summary-latest-year-404

Conversation

@TAEW00KIM
Copy link
Contributor

이슈 배경


기존의 문제

  • recent-summary에서 year 기본값(2025) 고정으로, 연도가 바뀌면 최신 요약 조회가 어긋날 수 있었습니다.
  • 또한 존재하지 않는 엔드포인트 요청의 404 처리 기준도 명확히 맞출 필요가 있었습니다.

해결 방식

  • GET /leagues/recent-summary의 year를 선택 파라미터로 변경했습니다.
    • year 미입력 시 서버에서 최근 종료 대회 연도를 자동 선택하도록 조회 로직을 보강했습니다.
  • 존재하지 않는 엔드포인트 요청은 404를 반환하도록 처리/검증을 추가했습니다.
    • 관련 Controller/Service/Acceptance 테스트와 REST Docs를 함께 갱신했습니다.

확인해야 할 부분

  • 프론트에서 year를 생략한 호출 방식으로 바로 사용 가능한지
스크린샷 2026-02-12 오후 12 35 08

@TAEW00KIM TAEW00KIM requested a review from Jin409 February 12, 2026 03:35
@TAEW00KIM TAEW00KIM self-assigned this Feb 12, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello @TAEW00KIM, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 recent-summary API의 유연성을 높이고, 잘못된 엔드포인트 요청에 대한 견고한 오류 처리를 제공합니다. year 파라미터가 선택 사항이 되어 클라이언트가 연도를 지정하지 않아도 최신 데이터를 자동으로 가져올 수 있게 되었으며, 존재하지 않는 경로에 대한 404 응답 처리를 통해 API의 안정성과 사용자 경험을 향상시켰습니다.

Highlights

  • Recent Summary API Year Parameter Optionality: The 'year' parameter for the '/leagues/recent-summary' endpoint has been made optional. If not provided, the server will now automatically determine the year of the most recently finished league.
  • 404 Handling for Non-existent Endpoints: Robust 404 error handling has been implemented for requests to non-existent API endpoints, returning an appropriate 'Not Found' response.
  • Documentation and Test Updates: All relevant Controller, Service, Acceptance tests, and REST Docs have been updated to reflect these changes, ensuring consistency and correctness.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/main/java/com/sports/server/common/advice/ControllerExceptionAdvice.java
    • NoHandlerFoundException을 처리하여 존재하지 않는 엔드포인트에 대한 404 응답을 반환하도록 로직을 추가했습니다.
  • src/main/java/com/sports/server/query/application/LeagueQueryService.java
    • findRecentSummary 메서드에서 year 파라미터가 null일 경우, leagueQueryRepository를 통해 최근 종료된 대회의 연도를 찾아 사용하도록 변경했습니다.
    • 이를 위해 getTargetYear 헬퍼 메서드를 추가했습니다.
  • src/main/java/com/sports/server/query/presentation/LeagueQueryController.java
    • recent-summary 엔드포인트의 year @RequestParamrequired = false로 변경하여 선택적 파라미터로 만들었습니다.
  • src/main/java/com/sports/server/query/repository/LeagueQueryRepository.java
    • 최근 종료된 대회의 연도를 조회하는 findRecentFinishedLeagueYears 쿼리 메서드를 추가했습니다.
  • src/main/resources/static/docs/api.html
    • recent-summary API 문서에서 year 파라미터의 기본값 설명을 업데이트하고, 예제 요청에서 year 파라미터를 제거했습니다.
    • 문서 업데이트 시간도 갱신했습니다.
  • src/test/java/com/sports/server/query/acceptance/LeagueQueryAcceptanceTest.java
    • recent-summary 테스트에서 year 파라미터를 제거하고, 존재하지 않는 엔드포인트에 대한 404 응답을 확인하는 새로운 인수 테스트를 추가했습니다.
  • src/test/java/com/sports/server/query/application/LeagueQueryServiceTest.java
    • recent-summary 관련 테스트 메서드 이름을 변경하고, year 파라미터를 null로 설정하여 서비스 로직의 변경 사항을 테스트하도록 수정했습니다.
  • src/test/java/com/sports/server/query/presentation/LeagueQueryControllerTest.java
    • recent-summary 컨트롤러 테스트에서 year 파라미터가 제거되었고, 서비스 호출 시 null을 전달하도록 변경했습니다.
    • REST Docs의 year 파라미터 설명을 업데이트했습니다.
Activity
  • 현재까지 이 Pull Request에 대한 사람의 활동(댓글, 리뷰 등)은 없습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This PR successfully implements fallback logic for the year parameter in the recent-summary endpoint, making it optional and selecting the most recent finished league year. It also adds a global exception handler for NoHandlerFoundException to provide a clean 404 response for non-existent endpoints. While the logic improvements are sound, a critical security concern has been identified: a potential unbounded resource allocation issue exists where the topScorerLimit parameter is used in a database query without an upper bound check, which could be exploited to cause a Denial of Service. Additionally, there are a few minor suggestions to improve code quality and maintainability.

List<PlayerGoalCountWithRank> topScorerResults = safeTopScorerLimit == 0
? Collections.emptyList()
: leagueTopScorerRepository.findTopPlayersByYearWithTotalGoals(year, PageRequest.of(0, safeTopScorerLimit));
: leagueTopScorerRepository.findTopPlayersByYearWithTotalGoals(targetYear, PageRequest.of(0, safeTopScorerLimit));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The topScorerLimit parameter is used to create a PageRequest without an upper bound check. An attacker can provide an extremely large value for this parameter (e.g., 2147483647), which may lead to excessive memory allocation or database performance issues, potentially causing a Denial of Service (DoS). It is recommended to validate the input and enforce a maximum allowable limit (e.g., 100).

@ExceptionHandler(NoHandlerFoundException.class)
protected ResponseEntity<ErrorResponse> handleNotFoundEndpointException(NoHandlerFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ErrorResponse.of("요청한 엔드포인트를 찾을 수 없습니다."));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

오류 메시지를 문자열 리터럴로 직접 사용하는 것보다 상수로 정의하여 관리하는 것이 좋습니다. 이렇게 하면 메시지의 일관성을 유지하고, 향후 수정이 필요할 때 더 쉽게 관리할 수 있습니다. 이 클래스 내에 private static final String 상수로 정의하거나, 별도의 ErrorMessage 클래스를 만들어 관리하는 것을 고려해 보세요.

}
return leagueQueryRepository.findRecentFinishedLeagueYears(now, PageRequest.of(0, 1)).stream()
.findFirst()
.orElse(LocalDate.now().getYear());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

fallback 로직에서 LocalDate.now()를 새로 호출하는 대신, 파라미터로 전달받은 now를 사용하는 것이 일관성 있고 테스트 용이성 측면에서 더 좋습니다. now.getYear()를 사용하도록 수정하는 것을 제안합니다.

Suggested change
.orElse(LocalDate.now().getYear());
.orElse(now.getYear());

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 수정하는 게 좋겠네요!

Copy link
Contributor

@Jin409 Jin409 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨어요~!

import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커밋 두개로 분리해주셨으면 더 좋았을 것 같아요! 👍👍

}
return leagueQueryRepository.findRecentFinishedLeagueYears(now, PageRequest.of(0, 1)).stream()
.findFirst()
.orElse(LocalDate.now().getYear());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 수정하는 게 좋겠네요!

.body(ErrorResponse.of(e.getBindingResult()));
}

@ExceptionHandler(NoHandlerFoundException.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 테스트 추가 해주시면 좋을 것 같아요! RestAssured 활용 해 보시면 될 것 같습니당

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 확인했습니다! 수정이랑 추가해서 머지해둘게요

Comment on lines +16 to +19
@TestPropertySource(properties = {
"spring.mvc.throw-exception-if-no-handler-found=true",
"spring.web.resources.add-mappings=false"
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 왜 필요한가요? 저희 기존 패턴이랑 안맞는 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

404 자체가 아니라 NoHandlerFoundException 핸들러가 실제로 호출되는지 검증하려고 넣었습니다!
기존에는 없는 엔드포인트 요청이 404 처리로만 끝날 수도 있어서 핸들러 테스트가 안되더라구요. 테스트에서만 예외 강제로 실행시키려고 넣었는데 빼야한다면 다시 빼서 커밋할게요

Copy link
Contributor

@Jin409 Jin409 Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 MVC 레이어에서 바로 걸러져서 그렇군요 이해했습니다 👍👍 머지 고고
머지 하시고 성민님한테 전달 주시면 좋을 것 같아요!

@Jin409 Jin409 force-pushed the refactor/recent-summary-latest-year-404 branch from fd83279 to ecb6bba Compare February 15, 2026 07:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants