외부 API를 사용하여 해외 축구 결과를 조회할 수 있는 토이 플젝을 시작했다.
먼저 API 호출을 위해 데이터가 간단한, 선수 데이터를 호출했다.
데이터가 정상적으로 조회되었으나 뭔가 불편한 생각이 든다.
1. 리그, 팀, 경기 등의 데이터를 호출할 때마다 uri, header 코드를 각 서비스마다 작성해줘야한다.
2. 간단한 GET 요청에 exchange()를 사용하는 것이 맞는걸까.
물론 exchange()를 통해 요청을 더욱 세밀하게 제어할 수 있다.
하지만 간단한 GET 요청이며 코드가 반복되는 상황을 최대한 줄이고 싶다.
RestTemplate을 생성할 때 uri와 header 값을 같이 넣어준다면 마지막 코드 한 줄로 정리되지 않을까.
RestTemplate Interceptor
- 인증 헤더 추가, 로그 기록, 요청/응답 수정 작업이 가능하다.
- ClientHttpRequestInterceptor 인터페이스를 구현하여 인터셉터를 만들 수 있다.
public class RestTemplateClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private final String headerName;
private final String headerValue;
public RestTemplateClientHttpRequestInterceptor(String headerName, String headerValue) {
this.headerName = headerName;
this.headerValue = headerValue;
}
@NonNull
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().add(headerName, headerValue);
return execution.execute(request, body);
}
}
@Configuration
@RequiredArgsConstructor
public class RestTemplateConfig {
private final RestTemplateBuilder restTemplateBuilder;
@Value("${api.baseUrl}")
private String baseUrl;
@Value("${api.token}")
private String apiToken;
@Bean
public RestTemplate restTemplate() {
return restTemplateBuilder
.rootUri(baseUrl)
.additionalInterceptors(new RestTemplateClientHttpRequestInterceptor("X-Auth-Token", apiToken))
.setConnectTimeout(Duration.ofMinutes(3))
.build();
}
}
api 호출에 필요한 baseUrl과 header 값을 함께 Bean으로 등록함으로써, 각 서비스마다 추가해야 할 코드가 줄었다.
private final RestTemplate restTemplate;
@Override
public PersonSearchResponse findById(Long id) {
ResponseEntity<PersonSearchResponse> forDto =
restTemplate.getForEntity("/persons/" + id, PersonSearchResponse.class);
return forDto.getBody();
}
현재는 api 호출에 필요한 코드만 작성되었다.
Request/Response 에 대한 로깅, 예외 처리에 대한 코드 추가가 필요하다.
[참고]
https://github.com/cheese10yun/spring-guide/blob/master/docs/api-call-guide.md