API通信
🌐 Spring BootでのAPI通信
Section titled “🌐 Spring BootでのAPI通信”Spring Bootでは、RestTemplateやWebClientを使用して、外部APIとの通信を簡単に実装できます。この章では、REST APIとの通信方法について詳しく解説します。
📋 RestTemplateの基本使用
Section titled “📋 RestTemplateの基本使用”RestTemplateは、Spring Frameworkが提供する同期HTTPクライアントです。
基本的な設定
Section titled “基本的な設定”@Configurationpublic 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); }}GETリクエスト
Section titled “GETリクエスト”@Servicepublic 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()); }}POSTリクエスト
Section titled “POSTリクエスト”@Servicepublic 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(); }}PUT/DELETEリクエスト
Section titled “PUT/DELETEリクエスト”@Servicepublic 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クライアントです。
WebClientの設定
Section titled “WebClientの設定”@Configurationpublic 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(); }}WebClientでのGETリクエスト
Section titled “WebClientでのGETリクエスト”@Servicepublic 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); }}WebClientでのPOSTリクエスト
Section titled “WebClientでのPOSTリクエスト”@Servicepublic 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); }}エラーハンドリング
Section titled “エラーハンドリング”API通信時のエラーを適切に処理します。
@Servicepublic 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()); } }}リトライ機能の実装
Section titled “リトライ機能の実装”一時的なエラーに対してリトライ機能を実装します。
@Configurationpublic 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; }}ロギングとモニタリング
Section titled “ロギングとモニタリング”API通信をログに記録し、モニタリングします。
@Service@Slf4jpublic 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通信を実現できます。