RU | EN | DE

1. RestTemplate (синхронный клиент)

📌 Старый, но до сих пор используется. В Spring 6 считается устаревающим, но знать надо.

📄 Bean-конфигурация:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(3))
                .setReadTimeout(Duration.ofSeconds(5))
                .build();
    }
}

📄 Примеры использования:

@Service
@RequiredArgsConstructor
public class WeatherService {
    private final RestTemplate restTemplate;
    public WeatherDto getWeather(String city) {
        String url = "https://api.weather.com/city/" + city;
        return restTemplate.getForObject(url, WeatherDto.class);
    }
    public void createUser(UserDto user) {
        restTemplate.postForEntity("http://localhost:8080/api/users", user, Void.class);
    }
}

2. WebClient (реактивный клиент)

📌 Современная альтернатива RestTemplate. Поддерживает асинхронность и реактивность.

📄 Bean-конфигурация:

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder.baseUrl("https://api.weather.com")
                      .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                      .build();
    }
}

📄 Использование:

@Service
@RequiredArgsConstructor
public class WeatherService {
    private final WebClient webClient;
    public Mono<WeatherDto> getWeather(String city) {
        return webClient.get()
                        .uri("/city/{city}", city)
                        .retrieve()
                        .bodyToMono(WeatherDto.class);
    }
 
    public Flux<UserDto> getUsers() {
        return webClient.get()
                        .uri("/api/users")
                        .retrieve()
                        .bodyToFlux(UserDto.class);
    }
}
 
📌 Mono<T> = один объект (аналог Optional),  
Flux<T> = поток объектов (как List).

3. OpenFeign (декларативный клиент)

📌 Если у тебя микросервисы → лучший выбор. Не нужно вручную писать RestTemplate или WebClient.

📄 Зависимость:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

📄 Включение:

@SpringBootApplication
@EnableFeignClients
public class DemoApplication {}

📄 Интерфейс-клиент:

@FeignClient(name = "userClient", url = "http://localhost:8080/api/users")
public interface UserClient {
    @GetMapping("/{id}")
    UserDto getUser(@PathVariable Long id);
    @PostMapping
    UserDto createUser(@RequestBody UserDto dto);
}

📄 Использование:

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserClient client;
    public UserDto get(Long id) {
        return client.getUser(id);
    }
}

4. Retry & Timeout (Resilience4j)

📌 Иногда внешнее API падает → надо повторять или ограничивать время ожидания.

📄 Зависимость:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>

📄 Конфигурация:

resilience4j.retry:
  instances:
    apiRetry:
      maxAttempts: 3
      waitDuration: 2s

📄 Использование:

@Service
public class ExternalService {
    @Retry(name = "apiRetry")
    public String callApi() {
        if (Math.random() > 0.7) {
            return "Success!";
        }
        throw new RuntimeException("API failed");
    }
}

5. Circuit Breaker (предохранитель)

📌 Чтобы не завалить сервис постоянными запросами, если он уже падает.

📄 Конфигурация:

resilience4j.circuitbreaker:
  instances:
    apiBreaker:
      failureRateThreshold: 50
      waitDurationInOpenState: 10s
      slidingWindowSize: 10

📄 Использование:

@Service
public class ExternalService {
    @CircuitBreaker(name = "apiBreaker", fallbackMethod = "fallback")
    public String callApi() {
        throw new RuntimeException("API error");
    }
    public String fallback(Throwable t) {
        return "Fallback response";
    }
}

6. Async API calls (параллельные запросы)

CompletableFuture:

@Async
public CompletableFuture<UserDto> fetchUser(Long id) {
    return CompletableFuture.supplyAsync(() -> client.getUser(id));
}

WebClient:

Flux<UserDto> users = webClient.get()
    .uri("/api/users")
    .retrieve()
    .bodyToFlux(UserDto.class);

7. Best Practices

  • ✅ Для синхронных API → RestTemplate (устаревающий, но встречается).
  • ✅ Для асинхронных/реактивных сервисов → WebClient.
  • ✅ Для микросервисов → Feign.
  • ✅ Добавляй retry, timeout, circuit breaker через Resilience4j.
  • ✅ Никогда не делай внешние вызовы без таймаутов.
  • ✅ Логируй все запросы/ответы (Spring Boot Sleuth или кастомный LoggingInterceptor).