[fix] 종료된 네이버 책 API를 알라딘으로 전환 (#372) - #373
Conversation
parseBookDetail()이 channel이 없거나 item이 비어있는 비정상 응답을 받으면 null을 반환해 호출부에서 NPE로 이어지던 문제를 수정. ExternalApiException을 명시적으로 던지도록 변경. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
네이버가 책 검색 Open API(book.xml, book_adv.xml)를 종료하여 (SE05: 존재하지 않는 검색 api) 책 검색/상세조회가 500으로 실패하던 문제 해결. - AladinApiUtil에 ItemSearch(키워드 검색) 호출/파싱 추가, ItemLookUp 파싱을 title/author/publisher/cover/description까지 확장 - AladinApiClient/CompositeBookApiAdapter가 naverApiClient 대신 aladinApiClient를 호출하도록 교체 (NaverApiClient/NaverBookXmlParser 등 네이버 관련 클래스는 삭제하지 않고 그대로 유지) - loadBookWithPageByIsbn()이 상세정보+페이지수를 알라딘 ItemLookUp 1회 호출로 함께 조회하도록 통합 (기존엔 naver+aladin 2회 호출) - RestTemplate에 사전 인코딩된 키워드를 그대로 넘기면 이중 인코딩되어 검색이 깨지는 문제가 있어, URI 템플릿 변수로 전달하도록 수정 - 알라딘 정책상 검색 결과가 200건까지만 조회 가능하여, totalElements를 200으로 캡핑해서 페이지네이션 last 플래그가 정확한 지점에서 true가 되도록 처리 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BookApiQueryPort는 provider(네이버/알라딘)에 무관해야 하는데 반환 타입에 "Naver"가 박혀있어 실제로는 알라딘 데이터를 담는데도 이름이 헷갈리는 문제가 있었음. - NaverBookParseResult -> BookSearchResult, 중첩 타입 NaverBook -> BookSummary - NaverDetailBookParseResult -> BookDetailResult - 위 리네이밍에 따라 다운스트림 전체(BookSearchService, BookApiQueryPort, BookDetailSearchResult 등) 및 테스트 코드의 import/타입명 갱신 - 리네이밍 김에 naverDetailBook/naverResult/naverBook 등 남아있던 변수·필드명도 provider-중립적으로 함께 정리 로직 변경 없음, 순수 리네이밍. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
FeedCreateService/BookSavedService가 책을 새로 저장할 때 상세정보만 조회하고 페이지 수는 null로 저장한 뒤, 방 생성 시점에 별도로 채워넣는 구조였음. 네이버(상세)+알라딘(페이지)로 provider가 나뉘어 있던 시절엔 합리적인 절약이었으나, 이제 알라딘 ItemLookUp 하나가 상세정보+페이지수를 함께 주기 때문에 더 이상 아낄 이유가 없음. - 두 서비스 모두 findDetailBookByIsbn() 대신 이미 있던 bookApiQueryPort.loadBookWithPageByIsbn(isbn)을 사용하도록 변경 (API 호출 횟수는 그대로 1회, 페이지 수까지 함께 저장됨) - RoomCreateService의 페이지 수 백필 로직은 기존 DB 데이터(페이지 수 null인 책들)를 위한 안전장치로 유지 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
FEED_CREATE/BOOK_SEARCH/BOOK_DETAIL_SEARCH API 문서에 BOOK_NAVER_API_* 에러코드가 나열되어 있었는데, 이제 이 API들은 네이버를 호출하지 않아 해당 에러를 절대 던질 수 없음. 실제로 발생 가능한 BOOK_ALADIN_API_PARSING_ERROR / BOOK_ALADIN_API_ISBN_NOT_FOUND로 교체 (키워드 검색은 ISBN_NOT_FOUND를 던지지 않으므로 PARSING_ERROR만 남김). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
findDetailBookByIsbn() 메서드명이 편집 과정에서 깨져 있어 컴파일이 되지 않던 문제 수정. c6889383에서 함께 반영됐어야 할 내용. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WalkthroughNaver 전용 도서 검색·상세 DTO를 공통 DTO로 변경했습니다. 검색과 ISBN 상세 조회를 Aladin API에 위임했습니다. 상세 정보와 페이지 수를 한 번에 조회하도록 변경하고, 서비스·웹 응답·오류 코드·테스트를 새 결과 타입에 맞게 수정했습니다. Changes도서 API 전환
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant BookQueryController
participant CompositeBookApiAdapter
participant AladinApiClient
participant AladinApiUtil
Client->>BookQueryController: 도서 검색 또는 ISBN 상세 조회
BookQueryController->>CompositeBookApiAdapter: 도서 조회 요청
CompositeBookApiAdapter->>AladinApiClient: Aladin 조회 위임
AladinApiClient->>AladinApiUtil: 검색·상세 파싱 요청
AladinApiUtil-->>AladinApiClient: 공통 도서 결과 반환
AladinApiClient-->>CompositeBookApiAdapter: 검색 결과 또는 상세 결과 반환
CompositeBookApiAdapter-->>BookQueryController: 응답 데이터 반환
BookQueryController-->>Client: 도서 응답 반환
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Test Results498 tests 498 ✅ 47s ⏱️ Results for commit d245fdf. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java (1)
82-149: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winAladin JSON 응답 전처리를 추가하세요.
fetchDetail과searchBooks는readTree(response)를 호출하기 직전에 response가null이면NullPointerException이 발생하지만, 현재 예외 핸들링은 이 경우를 처리하지 못합니다. 또한output=js응답은 JSON 외부 세미콜론을 포함할 수 있어 파서를 넘기기 전에 원본 문자열을 정제해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java` around lines 82 - 149, Update fetchDetail and searchBooks to preprocess response before objectMapper.readTree(response): handle null responses without allowing NullPointerException, and remove any trailing semicolon from output=js responses before parsing. Route these invalid-response cases through the existing ExternalApiException(BOOK_ALADIN_API_PARSING_ERROR) handling while preserving normal JSON parsing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java`:
- Around line 90-115: Update the Aladin response parsing around subInfo and
PAGE_COUNT_PARSING_KEY so a missing itemPage is not converted to pageCount 0 by
asInt(). Explicitly detect the absent page value and apply the intended
compensation behavior, such as throwing the existing ExternalApiException, while
preserving normal parsing when itemPage is present.
- Around line 102-109: Update the author mapping in the BookDetailResult
construction within AladinApiUtil so Aladin’s combined author string is
normalized to the required author role, or use the API’s role-specific field
when available. Apply the same rule consistently to both lookup and search
result mappings, preserving the other detail fields unchanged.
- Around line 70-80: Update the flows in BookSearchService and
BookMostSearchRankService so page-count retrieval reuses the detail data already
loaded by findDetailBookByIsbn instead of calling findPageCountByIsbn and
triggering fetchDetail twice. Prefer the existing loadBookWithPageByIsbn path,
or pass/cache the fetched AladinDetailResult through the flow while preserving
the current result behavior.
---
Outside diff comments:
In `@src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java`:
- Around line 82-149: Update fetchDetail and searchBooks to preprocess response
before objectMapper.readTree(response): handle null responses without allowing
NullPointerException, and remove any trailing semicolon from output=js responses
before parsing. Route these invalid-response cases through the existing
ExternalApiException(BOOK_ALADIN_API_PARSING_ERROR) handling while preserving
normal JSON parsing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 5d469ea0-b595-4ba3-a9be-cffed63f601e
📒 Files selected for processing (19)
src/main/java/konkuk/thip/book/adapter/in/web/response/BookDetailSearchResponse.javasrc/main/java/konkuk/thip/book/adapter/in/web/response/BookSearchListResponse.javasrc/main/java/konkuk/thip/book/adapter/out/api/CompositeBookApiAdapter.javasrc/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiClient.javasrc/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiParam.javasrc/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.javasrc/main/java/konkuk/thip/book/adapter/out/api/dto/BookDetailResult.javasrc/main/java/konkuk/thip/book/adapter/out/api/dto/BookSearchResult.javasrc/main/java/konkuk/thip/book/adapter/out/api/naver/NaverApiClient.javasrc/main/java/konkuk/thip/book/adapter/out/api/naver/NaverBookXmlParser.javasrc/main/java/konkuk/thip/book/application/port/in/BookSearchUseCase.javasrc/main/java/konkuk/thip/book/application/port/in/dto/BookDetailSearchResult.javasrc/main/java/konkuk/thip/book/application/port/out/BookApiQueryPort.javasrc/main/java/konkuk/thip/book/application/service/BookMostSearchRankService.javasrc/main/java/konkuk/thip/book/application/service/BookSavedService.javasrc/main/java/konkuk/thip/book/application/service/BookSearchService.javasrc/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.javasrc/main/java/konkuk/thip/feed/application/service/FeedCreateService.javasrc/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchApiTest.java
| public Integer getPageCount(String isbn) { | ||
| return fetchDetail(isbn).pageCount(); | ||
| } | ||
|
|
||
| public BookDetailResult getBookDetail(String isbn) { | ||
| return fetchDetail(isbn).detail(); | ||
| } | ||
|
|
||
| public AladinDetailResult getBookDetailWithPageCount(String isbn) { | ||
| return fetchDetail(isbn); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: findDetailBookByIsbn과 findPageCountByIsbn이 동일 흐름에서 함께 호출되는지 확인
rg -n -C 5 'findDetailBookByIsbn|findPageCountByIsbn|findDetailBookWithPageCountByIsbn|loadBookWithPageByIsbn' --type=javaRepository: THIP-TextHip/THIP-Server
Length of output: 162
🏁 Script executed:
#!/bin/bash
set -e
echo "== repo files matching relevant names =="
git ls-files | rg '(^|/)(AladinApiUtil|.*ApiAdapter|.*Book.*(Service|Controller|Repository)|.*Detail|.*Page).*\.java$|book|aladin|api)' | head -200
echo
echo "== Java method definitions/names containing relevant terms =="
rg -n -C 3 'getPageCount|getBookDetail|getBookDetailWithPageCount|fetchDetail|ItemLookUp|AladinDetailResult|BookDetailResult|pageCount|findDetail|findPage|aloadBook|loadBook' --type=java . | head -300
echo
echo "== AladinApiUtil snippet =="
cat -n src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java | sed -n '1,140p'
echo
echo "== call sites for AladinApiUtil methods (text search) =="
rg -n -C 4 'aladin(\.|)(get|find|getPage|getBook)::*|AladinApiUtil|getPageCount\(|getBookDetail\(|getBookDetailWithPageCount\(' --type=java .Repository: THIP-TextHip/THIP-Server
Length of output: 50380
🏁 Script executed:
#!/bin/bash
set -e
echo "== BookApiQueryPort =="
cat -n src/main/java/konkuk/thip/book/application/port/out/BookApiQueryPort.java | sed -n '1,140p'
echo
echo "== CompositeBookApiAdapter =="
cat -n src/main/java/konkuk/thip/book/adapter/out/api/CompositeBookApiAdapter.java | sed -n '1,120p'
echo
echo "== AladinApiClient =="
cat -n src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiClient.java | sed -n '1,80p'
echo
echo "== Direct invocations of BookApiQueryPort query methods =="
rg -n -C 4 '\b(\b(BookApiQueryPort|#|\.))?\s*(findDetailBookByIsbn|findPageCountByIsbn|loadBookWithPageByIsbn)\(' --type=java .Repository: THIP-TextHip/THIP-Server
Length of output: 17701
한 번 호출한 상세 정보는 페이지 수 조회에 재사용하세요.
BookSearchService, BookMostSearchRankService는 findDetailBookByIsbn으로 상세정보만 조회합니다. 이후 이 같은 흐름에서 findPageCountByIsbn을 또 호출하면 같은 ISBN으로 CompositeBookApiAdapter가 fetchDetail을 두 번 호출해서 알라딘 ItemLookUp 요청이 중복됩니다. 해당 경로에서는 loadBookWithPageByIsbn을 사용하거나, 상세정보를 캐시/전달해 중복 호출을 막아야 합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java`
around lines 70 - 80, Update the flows in BookSearchService and
BookMostSearchRankService so page-count retrieval reuses the detail data already
loaded by findDetailBookByIsbn instead of calling findPageCountByIsbn and
triggering fetchDetail twice. Prefer the existing loadBookWithPageByIsbn path,
or pass/cache the fetched AladinDetailResult through the flow while preserving
the current result behavior.
| // json 응답 결과에 item 키값이 없는 경우 | ||
| // TODO : 알라딘으로부터 page 정보가 없으면 ?? | ||
| // 보상 시나리오 : 유저에게 "page 정보를 찾을 수 없는 책입니다. 직접 page 정보를 입력하세요" 라고 안내 | ||
| // 일단 지금은 exception throw 만 진행 | ||
| if (!items.isArray() || items.isEmpty()) { | ||
| // TODO : 알라딘으로부터 page 정보가 없으면 ?? | ||
| // 보상 시나리오 : 유저에게 "page 정보를 찾을 수 없는 책입니다. 직접 page 정보를 입력하세요" 라고 안내 | ||
| // 일단 지금은 exception throw 만 진행 | ||
| throw new ExternalApiException(BOOK_ALADIN_API_ISBN_NOT_FOUND); | ||
| } | ||
|
|
||
| JsonNode subInfo = items.get(0).path(SUB_INFO_PARSING_KEY.getValue()); | ||
| JsonNode item = items.get(0); | ||
| JsonNode subInfo = item.path(SUB_INFO_PARSING_KEY.getValue()); | ||
| int pageCount = subInfo.path(PAGE_COUNT_PARSING_KEY.getValue()).asInt(); | ||
|
|
||
| return subInfo.path(PAGE_COUNT_PARSING_KEY.getValue()).asInt(); | ||
| BookDetailResult detail = BookDetailResult.builder() | ||
| .title(item.path("title").asText()) | ||
| .imageUrl(item.path("cover").asText()) | ||
| .author(item.path("author").asText()) | ||
| .publisher(item.path("publisher").asText()) | ||
| .isbn(item.path("isbn13").asText()) | ||
| .description(item.path("description").asText()) | ||
| .build(); | ||
|
|
||
| return new AladinDetailResult(detail, pageCount); | ||
| } catch (IOException e) { | ||
| throw new ExternalApiException(BOOK_ALADIN_API_PARSING_ERROR); | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
subInfo/itemPage 누락 시 pageCount가 조용히 0으로 저장됩니다.
코드 내 TODO 주석은 "알라딘으로부터 page 정보가 없으면" 사용자에게 안내하거나 예외를 던지는 보상 시나리오를 계획하고 있다고 설명합니다. 그러나 실제 구현은 items가 배열이 아니거나 비어 있는 경우(ISBN 자체를 찾지 못한 경우)만 예외를 던집니다. item은 존재하지만 subInfo.itemPage가 없는 경우, subInfo.path(PAGE_COUNT_PARSING_KEY.getValue()).asInt()는 조용히 0을 반환하고, 이 값이 그대로 pageCount로 반환되어 Book에 저장됩니다.
TODO 주석이 명시한 의도와 실제 동작이 다릅니다. pageCount가 0으로 저장된 책은 이후 진행률 계산 등에서 예상치 못한 결과를 낼 수 있습니다. itemPage 존재 여부를 확인하고, 없을 경우 명시적으로 처리(null 허용, 별도 플래그, 또는 예외)하는 것을 권장합니다.
이 TODO 주석에서 계획한 보상 시나리오(사용자 안내 또는 예외 처리)를 구현하는 코드를 생성해 드릴까요?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java`
around lines 90 - 115, Update the Aladin response parsing around subInfo and
PAGE_COUNT_PARSING_KEY so a missing itemPage is not converted to pageCount 0 by
asInt(). Explicitly detect the absent page value and apply the intended
compensation behavior, such as throwing the existing ExternalApiException, while
preserving normal parsing when itemPage is present.
| BookDetailResult detail = BookDetailResult.builder() | ||
| .title(item.path("title").asText()) | ||
| .imageUrl(item.path("cover").asText()) | ||
| .author(item.path("author").asText()) | ||
| .publisher(item.path("publisher").asText()) | ||
| .isbn(item.path("isbn13").asText()) | ||
| .description(item.path("description").asText()) | ||
| .build(); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
알라딘 API author 필드 지은이 옮긴이 형식
💡 Result:
알라딘 OpenAPI의 author 필드는 별도의 구조체로 분리되어 있지 않으며, 저자명, 옮긴이 등이 포함된 하나의 문자열(String) 형식으로 제공됩니다 [1][2][3]. 주요 특징은 다음과 같습니다: 1. 데이터 형식: author 필드는 작가가 여러 명인 경우를 포함하여 모든 저자 정보를 하나의 문자열로 묶어서 반환합니다 [3]. 2. 구성: 지은이(저자)와 옮긴이 등이 구분 기호와 함께 하나의 필드 내에 포함되어 있습니다 [3]. 별도의 '옮긴이' 필드가 독립적으로 존재하는 것이 아니므로, 필요한 경우 문자열 파싱(parsing)을 통해 데이터를 가공해야 합니다 [3]. 3. 추가 정보: 기본 API 응답 외에 더 상세한 작가 정보가 필요한 경우, API 설계에 따라 authors와 같은 별도의 상세 정보 목록을 요청할 수 있는 경우가 있으나, 기본적인 검색 및 상품 조회 결과에서 author 필드는 단일 문자열로 취급됩니다 [2][4]. 따라서 알라딘 API를 연동하여 지은이와 옮긴이를 각각 구분해야 한다면, 응답받은 author 문자열 내의 특정 구분자를 기준으로 파싱하는 처리가 필요합니다 [3].
Citations:
- 1: https://velog.io/@obb8923/%EC%9D%91%EB%8B%B5
- 2: https://velog.io/@obb8923/%EC%95%8C%EB%9D%BC%EB%94%98-API-%EC%A0%95%EB%A6%AC
- 3: https://myunji.tistory.com/472
- 4: https://velog.io/@obb8923/%EC%9A%94%EC%B2%AD-%EC%83%81%ED%92%88-%EA%B2%80%EC%83%89-API-%EB%AA%85%EC%84%B8%EC%84%9C
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
fd -a 'AladinApiUtil\.java|BookDetailResult\.java|BookSearchResult\.java' . | sed 's#^\./##'
echo
echo "== relevant lines =="
cat -n src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java | sed -n '70,170p'
echo
echo "== result author usages =="
rg -n "author\(|author:|BookDetailResult|BookSearchResult" src/main/java/konkuk/thip/book -SRepository: THIP-TextHip/THIP-Server
Length of output: 13611
알라딘 author 필드 정규화하거나 역할별 필드 사용하세요.
알라딘의 author는 지은이/옮긴이 정보가 하나의 문자열로 넘어올 수 있으므로, AladinApiUtil.java의 조회 및 검색 저자 매핑에 그대로 저장하면 저장·표시되는 저자 형식이 불일치할 수 있습니다. 필요 저자만 추출하도록 파싱하거나, API 문서의 역할 구분 필드는 다른 필드로 매핑하도록 변경하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/konkuk/thip/book/adapter/out/api/aladin/AladinApiUtil.java`
around lines 102 - 109, Update the author mapping in the BookDetailResult
construction within AladinApiUtil so Aladin’s combined author string is
normalized to the required author role, or use the API’s role-specific field
when available. Apply the same rule consistently to both lookup and search
result mappings, preserving the other detail fields unchanged.
#️⃣ 연관된 이슈
📝 작업 내용
문제 상황
2026-08-02 17:35:28, 유저(id=332)의
/books/{isbn}상세검색 요청에서 NPE 발생.조사 결과 네이버가 책 검색 Open API(
book.xml,book_adv.xml)를 완전히 종료한 것으로 확인됨(등록된 client ID로 호출해도
errorCode: SE05, 존재하지 않는 검색 api응답). 책 검색(/books),책 상세조회(
/books/{isbn}) 두 API 모두 정상 동작하지 않는 상태였음.원인
NaverBookXmlParser.parseBookDetail()이 파싱 실패(channel 없음/item 없음) 시 예외 없이null을반환했고, 이
null이BookDetailSearchResult.naverDetailBook에 그대로 담겨 컨트롤러 응답 생성단계에서 NPE로 이어짐. 근본 원인은 네이버 API 자체가 더 이상 응답하지 않는다는 것.
해결
이미 부분적으로 연동되어 있던 알라딘(Aladin) Open API로 책 검색/상세조회를 전면 전환함.
NaverBookXmlParser)ItemSearch(키워드 검색) 연동 추가,ItemLookUp(상세조회) 파싱을 title/author/publisher/cover/description까지 확장 (
AladinApiUtil/AladinApiClient)CompositeBookApiAdapter가 네이버 대신 알라딘을 호출하도록 교체.NaverApiClient/NaverBookXmlParser등 네이버 관련 클래스는 삭제하지 않고 그대로 유지(롤백 대비 및 향후 폴백 연동 시 참고용)
ItemLookUp1회 호출로 통합 (기존 naver+aladin 2회 호출 → 1회)RestTemplate에 사전 인코딩된 키워드를 그대로 넘기면 이중 인코딩되어 검색이 깨지는 버그 발견 및 수정totalElements를 200으로 캡핑해서페이지네이션
last플래그가 정확한 지점에서 true가 되도록 처리BookApiQueryPort반환 DTO를 provider-중립적인 이름으로 변경(
NaverBookParseResult→BookSearchResult,NaverDetailBookParseResult→BookDetailResult등)FeedCreateService/BookSavedService가 책을 새로 저장할 때 페이지 수를null로 저장하던 것을,알라딘이 상세정보+페이지수를 한 번에 주므로
loadBookWithPageByIsbn()으로 함께 저장하도록 변경BOOK_NAVER_API_*에러코드를 실제로 발생 가능한BOOK_ALADIN_API_*로 정정API 응답 필드 구조(JSON shape)는 변경하지 않음. 테스트 501개 전체 통과 확인.
📸 스크린샷
💬 리뷰 요구사항
image.aladin.co.kr로 바뀝니다.이미지 도메인 화이트리스트(Next.js
remotePatterns, CSPimg-src등)에 추가 필요.author필드는"J.K. 롤링 (지은이), 강동혁 (옮긴이)"처럼역할 표시가 괄호로 붙어서 옵니다. 저자명을 그대로 노출하는 화면이 있다면 확인 필요.
BOOK_NAVER_API_*(80001~80009) 에러코드는 이제 발생하지 않고, 대신BOOK_ALADIN_API_PARSING_ERROR(80015),BOOK_ALADIN_API_ISBN_NOT_FOUND(80016)로 옵니다.프론트 에러코드 매핑에 반영 필요.
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit
새 기능
버그 수정