Retrofit для Java: Type-safe HTTP клиент для Android и Java
1. Что это и зачем нужна
Retrofit — это мощная и элегантная библиотека для Java (и Android), которая превращает HTTP API в Java-интерфейс. Вместо того чтобы вручную писать шаблонный код для создания HTTP-запросов, обработки ответов и парсинга JSON, Retrofit делает всю эту работу за вас. Она автоматически сериализует ваши Java-объекты в JSON (или другой формат) для отправки на сервер и десериализует ответы сервера обратно в Java-объекты. Это делает код чистым, читаемым и легко поддерживаемым.
Зачем она нужна? Представьте, что вам нужно написать приложение, которое общается с REST API (например, GitHub API, OpenWeatherMap или вашим собственным сервером). Без Retrofit вам пришлось бы использовать низкоуровневые классы вроде HttpURLConnection или HttpClient, вручную формировать URL, устанавливать заголовки, обрабатывать коды ошибок и парсить JSON. Это не только утомительно, но и чревато ошибками. Retrofit решает эти проблемы, предоставляя декларативный способ описания API. Вы просто создаете интерфейс с методами, аннотируете их (например, @GET, @POST), и Retrofit сам генерирует реализацию этого интерфейса.
Retrofit — это стандарт де-факто для работы с HTTP в мире Android и Java. Он тесно интегрируется с OkHttp (для эффективной работы с сетью) и Gson/Moshi (для сериализации JSON). Библиотека поддерживает синхронные и асинхронные запросы, загрузку файлов, аутентификацию, кэширование и множество других возможностей. Благодаря своей простоте и гибкости, Retrofit используется в тысячах приложений и сервисов по всему миру.
2. Установка
Retrofit распространяется через Maven Central. Для его использования в вашем проекте на Java (например, с Maven или Gradle) добавьте соответствующие зависимости. Обратите внимание, что вам также понадобится конвертер для сериализации (чаще всего Gson или Moshi) и сам OkHttp (который Retrofit использует под капотом).
Maven (pom.xml)
<!-- Retrofit -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Конвертер Gson (для JSON) -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.9.0</version>
</dependency>
<!-- OkHttp (обычно подтягивается автоматически, но можно явно указать версию) -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
Gradle (build.gradle)
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}
Важно: Версии могут устаревать. Всегда проверяйте актуальные версии на официальном сайте или в репозитории Maven Central. Если вы используете другой конвертер (например, Moshi или Jackson), замените converter-gson на соответствующий артефакт (converter-moshi, converter-jackson).
3. Быстрый старт — минимальный рабочий пример
Давайте напишем простой пример, который получает список пользователей с сервера JSONPlaceholder (тестовый REST API).
Шаг 1: Создайте модель данных (POJO)
// User.java
public class User {
private int id;
private String name;
private String username;
private String email;
// Геттеры (обязательны для Gson)
public int getId() { return id; }
public String getName() { return name; }
public String getUsername() { return username; }
public String getEmail() { return email; }
}
Шаг 2: Создайте интерфейс API
// ApiService.java
import retrofit2.Call;
import retrofit2.http.GET;
import java.util.List;
public interface ApiService {
@GET("users")
Call<List<User>> getUsers();
}
Шаг 3: Создайте экземпляр Retrofit и выполните запрос
// Main.java
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class Main {
public static void main(String[] args) {
// 1. Создаем Retrofit-билдер
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/") // Базовый URL
.addConverterFactory(GsonConverterFactory.create()) // Конвертер JSON
.build();
// 2. Создаем реализацию интерфейса
ApiService service = retrofit.create(ApiService.class);
// 3. Создаем "Call" объект
Call<List<User>> call = service.getUsers();
// 4. Выполняем запрос асинхронно
call.enqueue(new Callback<List<User>>() {
@Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
if (response.isSuccessful()) {
List<User> users = response.body();
for (User user : users) {
System.out.println(user.getName() + " (" + user.getEmail() + ")");
}
} else {
System.out.println("Ошибка: " + response.code());
}
}
@Override
public void onFailure(Call<List<User>> call, Throwable t) {
System.err.println("Ошибка сети: " + t.getMessage());
}
});
// Ждем завершения асинхронного запроса (для демонстрации)
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Этот код выведет в консоль имена и email первых 10 пользователей с тестового сервера.
4. Основные методы/функции/классы
Рассмотрим ключевые компоненты Retrofit, которые вы будете использовать постоянно.
4.1. Retrofit.Builder
Сигнатура: public static class Builder
Что делает: Это строитель (Builder pattern) для создания экземпляра Retrofit. Позволяет настроить базовый URL, конвертеры, HTTP-клиент (OkHttp), пул соединений и другие параметры.
Пример:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build())
.build();
4.2. Retrofit.create()
Сигнатура: public <T> T create(final Class<T> service)
Что делает: Создает реализацию вашего API-интерфейса. Возвращает прокси-объект, который перехватывает вызовы методов и преобразует их в HTTP-запросы.
Пример:
ApiService service = retrofit.create(ApiService.class);
4.3. @GET, @POST, @PUT, @DELETE, @PATCH
Сигнатура: @GET("relative/path"), @POST("relative/path") и т.д.
Что делает: Аннотации, которые указывают HTTP-метод и относительный путь запроса. Путь может содержать динамические сегменты (см. @Path).
Пример:
public interface ApiService {
@GET("users/{id}")
Call<User> getUser(@Path("id") int userId);
@POST("users")
Call<User> createUser(@Body User user);
@DELETE("users/{id}")
Call<Void> deleteUser(@Path("id") int userId);
}
4.4. @Path
Сигнатура: @Path("name") Type parameter
Что делает: Заменяет динамический сегмент в URL-пути на значение параметра метода. Имя в аннотации должно совпадать с именем в фигурных скобках в @GET или другом методе.
Пример:
@GET("users/{id}/posts")
Call<List<Post>> getUserPosts(@Path("id") int userId);
4.5. @Query и @QueryMap
Сигнатура: @Query("key") Type value, @QueryMap Map<String, String> options
Что делает: Добавляет параметры запроса (query parameters) к URL. @Query для одного параметра, @QueryMap для динамического набора параметров.
Пример:
@GET("users")
Call<List<User>> getUsers(@Query("page") int page, @Query("limit") int limit);
@GET("search")
Call<List<Result>> search(@QueryMap Map<String, String> filters);
4.6. @Body
Сигнатура: @Body Object body
Что делает: Аннотирует параметр метода, который будет сериализован в тело запроса (обычно в JSON или XML). Используется с @POST, @PUT, @PATCH.
Пример:
@POST("users")
Call<User> createUser(@Body User newUser);
@Headers
Сигнатура: @Header("Authorization") String token, @Headers({"Cache-Control: max-age=640000", "User-Agent: My-App"})
Что делает: Позволяет добавлять HTTP-заголовки к запросу. @Header используется для динамических заголовков (значение передается как параметр), @Headers — для статических.
Пример:
@GET("user/profile")
Call<Profile> getProfile(@Header("Authorization") String authToken);
@Headers("Content-Type: application/json")
@POST("data")
Call<ResponseBody> postData(@Body RequestData data);
4.8. Call<T>
Сигнатура: public interface Call<T> extends Cloneable
Что делает: Представляет собой один HTTP-запрос, который может быть выполнен. Содержит методы execute() (синхронный) и enqueue(Callback) (асинхронный). Также можно отменить запрос через cancel().
Пример:
// Синхронный вызов (блокирует поток)
Response<User> response = call.execute();
User user = response.body();
// Асинхронный вызов
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
// Обработка успешного ответа
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// Обработка ошибки сети
}
});
4.9. Response<T>
Сигнатура: public final class Response<T>
Что делает: Обертка для HTTP-ответа. Содержит код ответа (code()), заголовки (headers()), тело (body()), сообщение об ошибке (errorBody()) и информацию об успешности (isSuccessful()).
Пример:
if (response.isSuccessful()) {
User user = response.body();
System.out.println("Успех: " + user.getName());
} else {
System.out.println("Ошибка HTTP: " + response.code());
// Можно получить тело ошибки
ResponseBody errorBody = response.errorBody();
}
4.10. Callback<T>
Сигнатура: public interface Callback<T>
Что делает: Интерфейс с двумя методами: onResponse() (вызывается при получении ответа от сервера, даже если код ошибки 4xx или 5xx) и onFailure() (вызывается при ошибке сети, таймауте или проблемах с парсингом).
Пример