restfulAPI를 개발하다 보면 제공할 정보를 위해 만드는 경우도 많지만 반대로 필요한 OpenAPI 에 접근하여 원하는 데이터를 긁어와야 할 때도 많다.
실무에서 꽤 자주 썼는데 따로 정리한적은 없는 것 같아서 내가 실제로 자주 썼던 샘플코드를 하나 가져와봤다.
개발 환경
IDE : intelliJ
FrameWork : springboot 3.2.2 / JPA(Hibernate5)
Launguage : java 17
BuildTool : Gradle
TestTool : Junit5
구현 내용은 다음과 같다
- ResponseScrap
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ResponseScrap {
@NotNull
private String status;
@NotBlank
private Object data;
@NotNull
private Object errors;
}
data scrap 시 대상API 에서 리턴되는 규격에 맞는 dto를 생성했다. status, errors의 응답내용에 따라 원하는 대로 분기하여 서비스 로직을 구현할 수 있다. 응답데이터를 담는 용도이므로 @Setter 은 생략했다.
- connectTarget 함수
데이터를 긁어올 대상 URL 과 전송할 requestData를 파라미터로 지정한다. requestData는 필수사항은 아니고, 요청하는 url에 필요할 경우 상황에 맞게 사용할 수 있다.
private ResponseScrap connectTarget(String url, String requestScrap) throws IOException {
String responseData = "";
URL connectionTarget = new URL(url);
ObjectMapper mapper = new ObjectMapper();
StringBuilder sb = new StringBuilder();
BufferedReader br;
HttpURLConnection con = (HttpURLConnection) connectionTarget.openConnection();
con.setRequestMethod("POST");
//서버에 연결되는 Timeout 시간 설정 - 최소 1초 ~ 20초 명시 됨에 따라 20000 설정
con.setConnectTimeout(20000);
//InputStream 읽어 오는 Timeout 시간 설정 - 최소 1초 ~ 20초 명시 됨에 따라 20000 설정
con.setReadTimeout(20000);
// post data 가 있을 경우 true
con.setDoOutput(true);
//request setting
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
//데이터 삽입
log.info("requestScrap {} => " + requestScrap);
OutputStream os = con.getOutputStream();
byte[] input = requestScrap.getBytes("utf-8");
os.write(input, 0, input.length);
if(con.getResponseCode() == HttpStatus.OK.value()) {
log.info(" connect success ! url = {} " + url);
br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
responseData = sb.toString();
log.info("responseData {} => " + responseData);
br.close();
}
ResponseScrap responseScrap = new ObjectMapper().readValue(responseData, ResponseScrap.class);
if(responseScrap.getStatus().equals(ScrapStatus.FAIL.data())) {
throw new ApiException(ApiErrorCode.CANNOT_CONNECT_SCRAP_SITE);
}
return responseScrap;
}
- 테스트 코드 예제
@Test
@DisplayName("스크래핑_외부연결")
public void connectTargetUrl() throws IOException {
// given
String url = [원하는데이터];
String token = "12354";
JSONObject requestData = new JSONObject();
requestData.appendField("token", token);
URL connectionTarget = new URL(url);
ObjectMapper mapper = new ObjectMapper();
StringBuilder sb = new StringBuilder();
BufferedReader br;
HttpURLConnection con = (HttpURLConnection) connectionTarget.openConnection();
con.setRequestMethod("POST");
//서버에 연결되는 Timeout 시간 설정 - 최소 1초 ~ 20초 명시 됨에 따라 20000 설정
con.setConnectTimeout(20000);
//InputStream 읽어 오는 Timeout 시간 설정 - 최소 1초 ~ 20초 명시 됨에 따라 20000 설정
con.setReadTimeout(20000);
// post data 가 있을 경우 true
con.setDoOutput(true);
//request setting
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
//데이터 삽입
try(OutputStream os = con.getOutputStream()) {
byte[] input = requestData.toJSONString().getBytes("utf-8");
os.write(input, 0, input.length);
}
// when
br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
System.out.println(sb.toString());
br.close();
// then
assertEquals(con.getResponseCode() , HttpStatus.OK.value(), "연결 실패");
}
특정 토큰 인증값을 요구하는 API 에 대한 연결여부를 확인하는 테스트를 구성했다.
위 코드를 기반으로 데이터를 스크랩하는 것뿐만 아니라 원하는 URL로 결괏값을 리턴하는 API를 생성할 수도 있다.