Skip to content

API通信

Spring Bootでは、RestTemplateWebClientを使用して、外部APIとの通信を簡単に実装できます。この章では、REST APIとの通信方法について詳しく解説します。

RestTemplateは、Spring Frameworkが提供する同期HTTPクライアントです。

@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
// より詳細な設定
@Bean
public RestTemplate restTemplateWithTimeout() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 接続タイムアウト(ミリ秒)
factory.setReadTimeout(5000); // 読み取りタイムアウト(ミリ秒)
return new RestTemplate(factory);
}
}
@Service
public class ApiService {
private final RestTemplate restTemplate;
private static final String API_BASE_URL = "https://api.example.com";
public ApiService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// 単純なGETリクエスト
public String getData() {
String url = API_BASE_URL + "/data";
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return response.getBody();
}
// パラメータ付きGETリクエスト
public UserDTO getUser(Long id) {
String url = API_BASE_URL + "/users/{id}";
Map<String, Long> params = Map.of("id", id);
ResponseEntity<UserDTO> response = restTemplate.getForEntity(
url, UserDTO.class, params);
return response.getBody();
}
// URI変数を使用
public UserDTO getUserWithUriVariables(Long id) {
String url = API_BASE_URL + "/users/{id}";
ResponseEntity<UserDTO> response = restTemplate.getForEntity(
url, UserDTO.class, id);
return response.getBody();
}
// クエリパラメータ付き
public List<UserDTO> searchUsers(String name) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString(API_BASE_URL + "/users")
.queryParam("name", name);
ResponseEntity<UserDTO[]> response = restTemplate.getForEntity(
builder.toUriString(), UserDTO[].class);
return Arrays.asList(response.getBody());
}
}
@Service
public class ApiService {
private final RestTemplate restTemplate;
// 単純なPOSTリクエスト
public UserDTO createUser(UserCreateRequest request) {
String url = API_BASE_URL + "/users";
ResponseEntity<UserDTO> response = restTemplate.postForEntity(
url, request, UserDTO.class);
return response.getBody();
}
// ヘッダーを設定したPOSTリクエスト
public UserDTO createUserWithHeaders(UserCreateRequest request, String token) {
String url = API_BASE_URL + "/users";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(token);
HttpEntity<UserCreateRequest> entity = new HttpEntity<>(request, headers);
ResponseEntity<UserDTO> response = restTemplate.postForEntity(
url, entity, UserDTO.class);
return response.getBody();
}
// カスタムヘッダーを設定
public UserDTO createUserWithCustomHeaders(UserCreateRequest request) {
String url = API_BASE_URL + "/users";
HttpHeaders headers = new HttpHeaders();
headers.set("X-API-Key", "your-api-key");
headers.set("X-Request-ID", UUID.randomUUID().toString());
HttpEntity<UserCreateRequest> entity = new HttpEntity<>(request, headers);
ResponseEntity<UserDTO> response = restTemplate.postForEntity(
url, entity, UserDTO.class);
return response.getBody();
}
}
@Service
public class ApiService {
private final RestTemplate restTemplate;
// PUTリクエスト
public UserDTO updateUser(Long id, UserUpdateRequest request) {
String url = API_BASE_URL + "/users/{id}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<UserUpdateRequest> entity = new HttpEntity<>(request, headers);
ResponseEntity<UserDTO> response = restTemplate.exchange(
url, HttpMethod.PUT, entity, UserDTO.class, id);
return response.getBody();
}
// DELETEリクエスト
public void deleteUser(Long id) {
String url = API_BASE_URL + "/users/{id}";
restTemplate.delete(url, id);
}
// DELETEリクエスト(レスポンスを取得)
public ResponseEntity<Void> deleteUserWithResponse(Long id) {
String url = API_BASE_URL + "/users/{id}";
return restTemplate.exchange(
url, HttpMethod.DELETE, null, Void.class, id);
}
}

WebClientの使用(非推奨の代替)

Section titled “WebClientの使用(非推奨の代替)”

RestTemplateは非推奨となっており、WebClientが推奨されています。WebClientは非同期・非ブロッキングのHTTPクライアントです。

@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
// タイムアウト設定付き
@Bean
public WebClient webClientWithTimeout() {
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofSeconds(5))
.doOnConnected(conn ->
conn.addHandlerLast(new ReadTimeoutHandler(5))
.addHandlerLast(new WriteTimeoutHandler(5)));
ReactorClientHttpConnector connector =
new ReactorClientHttpConnector(httpClient);
return WebClient.builder()
.baseUrl("https://api.example.com")
.clientConnector(connector)
.build();
}
}
@Service
public class ApiService {
private final WebClient webClient;
public ApiService(WebClient webClient) {
this.webClient = webClient;
}
// 同期実行(ブロッキング)
public UserDTO getUser(Long id) {
return webClient.get()
.uri("/users/{id}", id)
.retrieve()
.bodyToMono(UserDTO.class)
.block();
}
// 非同期実行(推奨)
public Mono<UserDTO> getUserAsync(Long id) {
return webClient.get()
.uri("/users/{id}", id)
.retrieve()
.bodyToMono(UserDTO.class);
}
// エラーハンドリング付き
public Mono<UserDTO> getUserWithErrorHandling(Long id) {
return webClient.get()
.uri("/users/{id}", id)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response ->
Mono.error(new ClientException("Client error: " + response.statusCode())))
.onStatus(HttpStatus::is5xxServerError, response ->
Mono.error(new ServerException("Server error: " + response.statusCode())))
.bodyToMono(UserDTO.class);
}
}
@Service
public class ApiService {
private final WebClient webClient;
// POSTリクエスト
public Mono<UserDTO> createUser(UserCreateRequest request) {
return webClient.post()
.uri("/users")
.bodyValue(request)
.retrieve()
.bodyToMono(UserDTO.class);
}
// ヘッダー付きPOSTリクエスト
public Mono<UserDTO> createUserWithAuth(UserCreateRequest request, String token) {
return webClient.post()
.uri("/users")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.bodyValue(request)
.retrieve()
.bodyToMono(UserDTO.class);
}
}

API通信時のエラーを適切に処理します。

@Service
public class ApiService {
private final RestTemplate restTemplate;
public UserDTO getUser(Long id) {
try {
String url = API_BASE_URL + "/users/{id}";
ResponseEntity<UserDTO> response = restTemplate.getForEntity(
url, UserDTO.class, id);
return response.getBody();
} catch (HttpClientErrorException.NotFound e) {
throw new ResourceNotFoundException("User", id);
} catch (HttpClientErrorException e) {
throw new ApiException("API client error: " + e.getMessage());
} catch (HttpServerErrorException e) {
throw new ApiException("API server error: " + e.getMessage());
} catch (ResourceAccessException e) {
throw new ApiException("Connection error: " + e.getMessage());
}
}
}

一時的なエラーに対してリトライ機能を実装します。

@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplateWithRetry() {
RestTemplate restTemplate = new RestTemplate();
// リトライ可能なHTTPクライアント
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
CloseableHttpClient httpClient = HttpClients.custom()
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))
.build();
factory.setHttpClient(httpClient);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
}

API通信をログに記録し、モニタリングします。

@Service
@Slf4j
public class ApiService {
private final RestTemplate restTemplate;
public UserDTO getUser(Long id) {
String url = API_BASE_URL + "/users/{id}";
long startTime = System.currentTimeMillis();
try {
ResponseEntity<UserDTO> response = restTemplate.getForEntity(
url, UserDTO.class, id);
long duration = System.currentTimeMillis() - startTime;
log.info("API call successful: url={}, status={}, duration={}ms",
url, response.getStatusCode(), duration);
return response.getBody();
} catch (Exception e) {
long duration = System.currentTimeMillis() - startTime;
log.error("API call failed: url={}, duration={}ms", url, duration, e);
throw e;
}
}
}

Spring BootでのAPI通信は、以下の方法で実装できます:

  • RestTemplate: 同期HTTPクライアント(非推奨だが広く使用)
  • WebClient: 非同期・非ブロッキングHTTPクライアント(推奨)
  • エラーハンドリング: 適切な例外処理の実装
  • リトライ機能: 一時的なエラーへの対応
  • ロギング: API通信の監視とデバッグ

これらの機能を適切に使用することで、堅牢なAPI通信を実現できます。