외부 API xml파싱..삽질 기록⏱️

NTbell·2025년 3월 24일
post-thumbnail

이번 포스팅경우 외부API를 처음 다뤄보면서 삽질한 기록을 포스팅해볼려 한다..!

그렇다 필자는 공공데이터를 이용하고싶었다 그 중에서 공공데이터API를 이용해서 대학교리스트를 DB에 저장하고 싶었다!

그냥 시크릿키 발급해서 🪄 적용하면 끝 아닌가 쉽게 생각했다..ㅎ

우선 이용하기 앞서 지식이 필요했다 그래서 포스팅글과 스택오버플로우랑 스프링부트 docs를 읽으면서 이미 잘 정리해 놓으신 천재 개발자들이야 감탄하고 관련 정보를 정리했지만... 그것을 내가 적용하는데는 삽질을 하는 여정을 시작하게되었다

무튼 내가 참고한 자료는 아래와 같다 (내 포스팅 글도 포함 ㅎ)

RestTemplate vs WebClient 비교
Jackson 과 JAXB 성능 비교
HTTP Message Conversion
Message Converters
Http Message Converters with the Spring Framework

결론 적으로 외부API에서 제공해주는 형식은 XML이기 때문에
객체로 변환 후stream과 map을 이용해서 API 응답 데이터에서 원하는 값만 골라내어 엔티티에 매핑!

xml-> 객체 -> 엔티티 매핑


1️⃣ 태그확인

외부 API를 사용할 때 XML 구조에서 리스트 데이터를 어떻게 감싸져 있는지 확인할 방법이 필요했다

리스트 데이터를 표현할 때 태그로 감싸는 경우가 많다고 하지만 항상 은 아니기 때문에 API 설계자가 어떻게 정의했는지 확인인 필요 했다

@JacksonXmlElementWrapper(useWrapping = false) // 리스트를 감싸는 태그 비활성화, item 태그만 위에 감싸는 태그없이 item태그만 읽기위함

@JacksonXmlProperty(localName = "item")
private List<UniversityItem> items;

  • @JacksonXmlProperty(localName = "item")는 태그를 찾아서 List에 매핑
  • @JacksonXmlElementWrapper(useWrapping = false)는 "감싸는 태그()가 없으니 바로 태그들만 읽어!"라는 설정
<response>
	<item>
			<FCLTY_NM>서울대학교</FCLTY_NM>
	</item>
	<item>
			<FCLTY_NM>고려대학교</FCLTY_NM>
	</item>
</response>

만약 태그가 있다면?

<response>
    <items>
        <item>
            <FCLTY_NM>서울대학교</FCLTY_NM>
        </item>
        <item>
            <FCLTY_NM>고려대학교</FCLTY_NM>
        </item>
    </items>
</response>

@JacksonXmlElementWrapper(localName = "items") // 감싸는 태그 지정
@JacksonXmlProperty(localName = "item")
private List items;

  • useWrapping = false를 제거하거나 useWrapping = true로 설정하면 Jackson이 태그를 기대하게됨

그러므로 일일히 다 확인해봐야한다!

안에 태그가 있는것을 확인할 수 있었다


2️⃣ 디코더

내가 삽질한 경우는 위에 말한 것처럼 Jackson 이 성능이 좋다고 해서 이용할려 했다

Jackson 과 JAXB 가 사용하는 각각 어노테이션을 다르다

JAXB: @XmlRootElement, @XmlElement 등
Jackson: @JsonProperty, @JsonIgnore 등

데이터의 구조와 객체의 필드가 어떻게 매핑되는지 알려줘야한다
1. 필드 이름 불일치 해결
2. 데이터 구조 정의
를 위함이라고 생각하면 된다

무튼, 나는 Jackson 기준으로 어노테이션과 설정을 해줬다
또한 비동기로 처리하고싶기에 WebClient를 이용하였다

문제는 Jackson는 xml을 객체로 변경해주는 디코더가 없었다
아무래도 이걸로 삽질을 많이 한것같다
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/codec/xml/Jaxb2XmlDecoder.html

공식문서에서도 Jasck에서 json에서 객체로 변환해주는 것은 있어도 xml에서 객체로 변환해주는 것은 발견할 수 없었다

그리하여 Jaxb2Decoder를 이용해서 다시 변경하였다 해결하였다


3️⃣302응답

org.springframework.web.reactive.function.UnsupportedMediaTypeException: 
Content type 'text/html' not supported for bodyType

webClient가 외부 API 호출에서 받은 응답의 콘텐츠 타입(Content-Type)이 기대한 타입과 맞지 않을 때 발생 하는 예외도 발생을 했었고

302 경우 서버가 "여기 말고 다른 곳으로 가!"라고 클라이언트에게 말하는 것

비유

식당에 갔는데 "지금 이 자리 말고 저쪽으로 가세요"라고 안내 받은 상황

postman이나 크롬에서 직접 시크릿코드 넣고 할때는 이상이 없었지만 로컬서버에서 실행했을 때는 저 문제가 발생하였다

HttpClient httpClient = HttpClient.create()
    .followRedirect(true);

302 응답 → HTML 페이지 → UnsupportedMediaTypeException 발생.
followRedirect(true) 설정으로, 리다이렉트된 새 URL로 이동 → JSON/XML 응답을 받아 성공
해결


4️⃣ 동기 -> 비동기로

나는 대학교 리스트를 정보를 전부 받아오는 것을 원했기에 block(); 사용해서 동기로 처리해줘야하나 생각했지만

https://www.baeldung.com/java-fix-illegalstateexception-blocking

위 내용처럼 block() 같은 블록킹 작업을 Spring WebFlux에서 쓰지 말라는 것을 보고 비동기로 처리해줬다


5️⃣ @XmlAccessorType

나는 객체를 다음과 같은 이유로
OOP 원칙: 캡슐화를 통해 필드를 private로 설정
왜?: 객체 내부 데이터를 외부에서 직접 접근 못 하게 숨기고, Getter/Setter로 제어
이점: 데이터 보호, 변경 로직 관리 가능
문제 예시: public String universityName;이면 obj.universityName = "잘못된 값";로 누구나 망칠 수 있음

결론: private로 해서 데이터를 안전하게 지키고, 필요 시 메서드로만 다루게 하기위해 접근 지정자를 private설정했지만

JAXB가 접근 방식을 설정하지 않으면 Getter/Setter를 통해 접근하려고 함!
즉, @XmlAccessorType를 설정하지 않으면 기본값은 XmlAccessType.PUBLIC_MEMBER
이 경우, public 필드나 public Getter/Setter만 매핑 대상이 됨

@XmlAccessorType(XmlAccessType.FIELD)

JAXB에서 XML 데이터를 객체로 변환할 때, 어떤 방식으로 필드나 메서드에 접근할지 정의

  • XmlAccessType.FIELD: private, protected, public 등 접근 지정자 상관없이 필드 자체에 직접 접근해서 매핑

org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from GET http://safemap.go.kr/openApiService/data/getUniversity.do, but response failed with cause: org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144

데이터를 불러오는 과정에서 크기가 너무 커 기존 버퍼크기보다 초과하는 문제가 생겨

버퍼 크기를 10MB로 조정해서 해결하였다

🐈

외부 API에서 제공해주는 XML을 DB에 저장하느라 삽질을 많이하게 되었다. 하지만 공부는 많이 되었다 ㅎㅁㅎ

profile
어떤 개발자가 되고싶나

0개의 댓글