API 호출 기본 (URL, Reader, ObjectMapper)
환율 계산기를 만드려고 한다. 먼저 무료로 제공하고 있는 환율 데이터 API를 통해 환율을 가져오는 코드를 작성하려 한다.
이 부분에서 기존에 애매모호했던 내용을 정리하려한다.
1. java.net.URL
URL url = new URL("https://example.com");
URLConnection connection = url.openConnection();
URL클래스는 원격지원에 대한 연결을 생성할 때 사용된다. 그리고 openConnection() 메서드는 주어진 URL에 대한 URLConnection 객체를 반환한다.
- 연결 객체 생성: URL의 프로토콜에 맞는 URLConnection 객체를 생성한다. 예를 들어, http 프로토콜의 경우 HttpURLConnection 객체가 반환됩니다.
URL url = new URL("https://open.er-api.com/v6/latest/" + currency);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
상속을 통해 형변환이 가능하다.
설정 변경 가능: URLConnection 객체를 통해 시간 초과, 요청 메서드(POST, GET 등), 헤더 등 다양한 설정을 변경할 수 있다.
연결 수행: URLConnection 객체를 사용하여 원격 자원과의 실제 연결이 이루어지며, 이때부터 데이터를 송수신할 수 있다.
이번에는 수신의 용도로만 사용할 것이다.
1차
- 수신
InputStream inputStream = connection.getInputStream();
- 결과
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@f79e
뭔가 호출로 가져온 데이터가 주소로만 표시 되어있다.
2차
- 수신
InputStreamReader isr = new InputStreamReader(connection.getInputStream());
InputStreamReader는 InputStream 바이트 스트림을 Reader(문자스트림)으로 변환하는데 사용된다.
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
BufferedReader는 문자 스트림을 버퍼링하여 성능을 향상시킨다. BufferedReader는 내부 버퍼를 사용해 데이터를 일정량 모아서 처리하기 떄문에 매번 작은 데이터를 읽는 대신 한 번에 큰 데이터를 일겅 들이게 된ㄷ나. I/O 작업이 더 효율적이고 빠르게 이루어진다.
String response = br.lines().collect(Collectors.joining());
데이터를 한줄씩 읽어서 String 형태로 만들어 준다.
참고로 Collectors.joining()는 여러줄의 데이터를 한줄의 형태로 만들어 준다.
2. ObjectMapper
ObjectMapper mapper = new ObjectMapper();
ExRateData data = mapper.readValue(response, ExRateData.class);
BigDecimal exRate = data.rates().get("KRW");
그렇게 나온 데이터를 ObjectMapper를 이용해 DTO에 담아 줄 수 있다.
record를 사용해 만들어 준다. 파라미터가 필드의 값이 되어 생성자 만들으로도 dto를 생성할 수 있다.
public record ExRateData(String result, Map<String, BigDecimal> rates) {
}
참고로 이렇게만 담는다면,
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "provider" (class com.hellopayment.ExRateData), not marked as ignorable (2 known properties: "rates", "result"])
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2914] (through reference chain: com.hellopayment.ExRateData["provider"])
다음처럼 변환을 못한다는 오류가 난다. "provider"를 담을 곳이 없다고 뭐라 하는 것이다.
@JsonIgnoreProperties(ignoreUnknown = true)
public record ExRateData(String result, Map<String, BigDecimal> rates) {
}
담을 dto에 @JsonIgnoreProperties를 true로 사용해서 불필요한 json 데이터는 굳이 받지 않게 설정하면 된다.