Skip to content

[REFACTOR]: PaymentService 외부 API 호출 로직 분리#91

Merged
zerochani merged 4 commits intodevelopfrom
feature/payment
Jan 31, 2026
Merged

[REFACTOR]: PaymentService 외부 API 호출 로직 분리#91
zerochani merged 4 commits intodevelopfrom
feature/payment

Conversation

@zerochani
Copy link
Contributor

@zerochani zerochani commented Jan 31, 2026

💡 작업 개요

  • PaymentService의 복잡도를 낮추고 유지보수성을 높이기 위해 외부 API 호출 로직을 별도 서비스 TossPaymentService로 분리했습니다.

✅ 작업 내용

  • 기능 개발
  • 버그 수정
  • 리팩토링
  • 주석/포맷 정리
  • 기타 설정

🧪 테스트 내용

  • ./gradlew clean build 성공

Summary by CodeRabbit

  • Refactor
    • Centralized payment integration by moving external payment calls into a dedicated payment service. Confirmation and cancellation flows now use the centralized service with unified error handling and retained validation checks, improving reliability, consistency, and maintainability without changing user-facing payment behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 31, 2026

📝 Walkthrough

Walkthrough

Extracts Toss API calls into a new TossPaymentService; PaymentService now delegates confirm and cancel operations to that service, preserving existing validation and error handling.

Changes

Cohort / File(s) Summary
PaymentService refactor
src/main/java/com/eatsfine/eatsfine/domain/payment/service/PaymentService.java
Replaced direct RestClient usage with a TossPaymentService dependency; confirmPayment and cancelPayment now delegate to service methods; removed in-method REST call logic and try/catch blocks.
New TossPaymentService
src/main/java/com/eatsfine/eatsfine/domain/payment/service/TossPaymentService.java
Added service encapsulating Toss API interactions with confirm(dto) and cancel(paymentKey, dto) methods, centralized error handling and logging, injects qualified RestClient.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant PaymentService as PaymentService
    participant TossService as TossPaymentService
    participant RestClient as tossPaymentClient
    participant TossAPI as "Toss API"

    Client->>PaymentService: confirmPayment(dto) / cancelPayment(...)
    PaymentService->>TossService: confirm(dto) / cancel(paymentKey, dto)
    TossService->>RestClient: POST /v1/payments... (body)
    RestClient->>TossAPI: HTTP request
    TossAPI-->>RestClient: HTTP response
    RestClient-->>TossService: TossPaymentResponse
    TossService-->>PaymentService: TossPaymentResponse
    PaymentService-->>Client: validate response -> proceed / throw
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • sonjunkyu
  • SungMinju
  • twodo0

Poem

🐰 I hopped through code with nimble paws,
I moved Toss calls behind service doors,
Now PaymentService sends a note,
TossPaymentService takes the float,
Hooray — cleaner hops and fewer bores! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main refactoring change: separating external API call logic from PaymentService into a dedicated service.
Description check ✅ Passed The description follows the required template structure with all main sections completed: work overview, work type (refactoring checked), and test results provided.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/payment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

PaymentService의 외부 Toss 결제 API 호출 로직을 별도 서비스(TossPaymentService)로 분리해 결제 도메인 서비스의 복잡도를 낮추는 리팩토링입니다.

Changes:

  • Toss 결제 승인/취소 호출을 담당하는 TossPaymentService 신규 추가
  • PaymentService에서 RestClient 직접 호출을 제거하고 TossPaymentService로 위임

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/main/java/com/eatsfine/eatsfine/domain/payment/service/TossPaymentService.java Toss 결제 승인/취소 외부 API 호출을 캡슐화하는 서비스 추가
src/main/java/com/eatsfine/eatsfine/domain/payment/service/PaymentService.java Toss API 호출 로직을 신규 서비스로 분리하여 의존성/코드 복잡도 감소

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 83 to 90
// 토스 API 호출
TossPaymentResponse response;
try {
response = tossPaymentClient.post()
.uri("/v1/payments/confirm")
.body(dto)
.retrieve()
.body(TossPaymentResponse.class);

if (response == null || !"DONE".equals(response.status())) {
log.error("Toss Payment Confirmation Failed: Status is not DONE");
payment.failPayment();
throw new GeneralException(ErrorStatus._INTERNAL_SERVER_ERROR);
}
} catch (Exception e) {
log.error("Toss Payment API Error", e);
TossPaymentResponse response = tossPaymentService.confirm(dto);

if (response == null || !"DONE".equals(response.status())) {
log.error("Toss Payment Confirmation Failed: Status is not DONE");
payment.failPayment();
throw new GeneralException(ErrorStatus._INTERNAL_SERVER_ERROR);
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

confirmPayment에서 tossPaymentService.confirm(dto)가 예외(예: RestClient 4xx/5xx, 네트워크 오류)로 GeneralException을 던지면, 현재 로직은 payment.failPayment()를 호출하지 못한 채 메서드가 종료됩니다. 이 메서드는 @Transactional(noRollbackFor = GeneralException.class)이라서 예외가 발생해도 트랜잭션 롤백이 되지 않기 때문에 결제가 PENDING 상태로 남는 회귀가 발생할 수 있습니다. tossPaymentService.confirm(dto) 호출을 try/catch로 감싸서 예외 시에도 payment.failPayment()를 수행한 뒤 예외를 재던지도록 처리해 주세요.

Copilot uses AI. Check for mistakes.
public TossPaymentResponse cancel(String paymentKey, PaymentRequestDTO.CancelPaymentDTO dto) {
try {
return tossPaymentClient.post()
.uri("/v1/payments/" + paymentKey + "/cancel")
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

cancel()에서 URI를 문자열 덧셈으로 만들면 paymentKey에 특수문자/슬래시 등이 포함될 때 인코딩이 깨지거나 의도치 않은 경로가 구성될 수 있습니다. RestClient의 URI 템플릿(예: /v1/payments/{paymentKey}/cancel)이나 UriBuilder를 사용해 path variable로 바인딩하도록 변경해 주세요.

Suggested change
.uri("/v1/payments/" + paymentKey + "/cancel")
.uri("/v1/payments/{paymentKey}/cancel", paymentKey)

Copilot uses AI. Check for mistakes.
Comment on lines 18 to 20
private final RestClient tossPaymentClient;

public TossPaymentResponse confirm(PaymentConfirmDTO dto) {
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

현재 애플리케이션에는 RestClient 빈이 최소 2개(TossPaymentConfig.tossPaymentClient, RestClientConfig.businessWebClient) 존재합니다. 이 상태에서 RestClient 타입을 @Qualifier 없이 주입하면, 컴파일러의 파라미터 이름 보존 여부에 따라 런타임에 DI 후보가 모호해질 수 있습니다. tossPaymentClient 주입 지점에 @Qualifier("tossPaymentClient")(또는 @Primary 지정)로 빈을 명시해 주세요.

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@src/main/java/com/eatsfine/eatsfine/domain/payment/service/TossPaymentService.java`:
- Around line 33-41: In TossPaymentService.cancel, avoid string-concatenating
paymentKey into the URI; change the tossPaymentClient.post().uri(...) call to
use a URI template with a placeholder (e.g., "/v1/payments/{paymentKey}/cancel")
and pass paymentKey as the variable so the RestClient will encode reserved
characters properly; keep the subsequent
.body(dto).retrieve().body(TossPaymentResponse.class) behavior unchanged and
ensure you update the uri invocation that currently builds the path with "+"
concatenation.

@zerochani zerochani merged commit 429f91e into develop Jan 31, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants