현재 진행하고 있는 사이드 프로젝트에는 책 정보가 필요하다.
크롤링해서 DB에 직접 저장해두기엔 세상에 책이 너무 많아 효율도 안 나오고 무리다.
입맛에 맞게 재가공한 책 데이터만 내 DB에 따로 보관하고 싶은데.. 라고 생각하던 찰나
알라딘과 같은 대형 서점들은 OpenAPI를 오래전부터 제공하고 있다는 걸 알게 됐다!
본인들의 소중한 데이터를 제공하면서 얻는 이득이 얼마나 되는진 모르겠지만..
감사히 잘 쓰려고 한다.
제일 위에 있는 포스팅에서 "API 키 발급 및 URL 등록하기 ☞" 를 클릭하면 이런 화면이 뜬다.
로그인 창이 뜰텐데, OAuth로 연동된 계정으로는 키 발급을 받을 수 없으니 간편 회원가입을 하자.
다음은 주소를 추가하는 부분에 본인 서버의 도메인을 넣은 뒤 추가 버튼을 클릭하면 된다.
나는 도메인이 따로 없어서 내 블로크 링크를 넣었다. 발급은 바로 된다.
인증 키는 어디에도 노출시키지 않는 습관을 들이자.
그러다 AWS 같은 곳의 키를 유출하는 순간... 큰일난다.
Github 같은 곳에 올려놨다가 과금 폭탄 맞는 경우도 있다.
여기서는 API 명세서를 확인할 수 있다.
내가 어떤 형식으로 요청을 보내야 하는지, 응답 값은 어떤 형식으로 오는지 확인할 수 있다.
입맛에 맞게 URL을 수정해서 요청하면 된다.
public List<BookInfoResponse> searchBooks(String query, String queryType) {
List<BookInfoResponse> bookList = new ArrayList<>();
try {
if (query == null || query.isBlank() || queryType == null || queryType.isBlank()) {
return Collections.emptyList();
}
String encodedQuery = URLEncoder.encode(query, StandardCharsets.UTF_8);
StringBuilder sb = new StringBuilder("http://www.aladin.co.kr/ttb/api/ItemSearch.aspx");
sb.append("?ttbkey=").append(ttbKey);
sb.append("&Query=").append(encodedQuery);
sb.append("&QueryType=").append(queryType);
sb.append("&MaxResults=20&start=1&output=xml&Version=20131101");
URL url = new URL(sb.toString());
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(url.openStream());
document.getDocumentElement().normalize();
NodeList itemList = document.getElementsByTagName("item");
for (int i = 0; i < itemList.getLength(); i++) {
Node node = itemList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
BookInfoResponse book = BookInfoResponse.of(
getTagValue("title", element),
getTagValue("author", element),
getTagValue("description", element),
getTagValue("publisher", element),
getTagValue("isbn13", element),
getTagValue("cover", element),
parseReviewRank(getTagValue("customerReviewRank", element))
);
bookList.add(book);
}
}
} catch (IOException | ParserConfigurationException | SAXException e) {
log.error("알라딘 API 호출 또는 XML 파싱 중 오류 발생", e);
}
return bookList;
}
책 검색 요청을 처리하는 비즈니스 로직이다.
프론트 단에서 사용자가 검색 조건을 하나 선택하고 검색어를 입력하면, 그 정보를 기반으로 알라딘 OpenAPI에 요청을 보낸다.
검색 조건은 QueryType
(예: 제목, 저자, 출판사 등), 검색어는 Query
로 URL에 붙는데, 알라딘 명세에 따라 &Query=검색어&QueryType=조건
형태로 조합한다.
응답 XML에서 <item>
태그를 순회하면서 필요한 정보들을 추출하고, BookInfoResponse
객체로 변환해서 리스트로 담아 반환하는 구조다.
getTagValue()
private String getTagValue(String tag, Element element) {
NodeList nodeList = element.getElementsByTagName(tag);
if (nodeList.getLength() == 0) return "";
String text = nodeList.item(0).getTextContent();
return text != null ? text : "";
}
주어진 태그 이름에 해당하는 XML 요소에서 텍스트 값을 추출한다.
태그가 존재하지 않거나 값이 비어 있는 경우를 대비해 빈 문자열을 반환하도록 했다.
이부분은 크롤링을 해봤다면 이해하기 쉬울 거라 생각한다.
parseReviewRank()
private int parseReviewRank(String value) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return 0;
}
}
XML에서 전달되는 리뷰 평점(customerReviewRank)을 정수로 변환하며, 변환에 실패할 경우 기본값 0을 반환하도록 했다.
(💡+추가) 키 값 관리하는 법
1. application.properties 파일에 내가 원하는 변수명으로 선언
aladin.ttb.key=your-key
2. 키 값을 사용해야하는 클래스에 @Value
어노테이션과 함께 필드를 선언
@Value("${aladin.ttb.key}")
private String ttbKey;
3. properties 파일을 .gitignore 파일에 추가
*.properties
로컬의 .properties 파일에 정의한 키 값이 자동으로 변수(ttbKey)에 주입된다.
application.yml 예시
aladin:
ttb:
key: your-key
제목에 'Java'를 포함한 검색 결과는 아래와 같다.
이렇게 데이터를 재가공해서 뿌려줄 수 있다!
OpenAPI들을 잘 활용하면 개발에 필요한 더미 데이터들도 쉽게 구할 수 있다.