Retrofit для Kotlin: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Retrofit и зачем он нужен?

Retrofit — это типобезопасный HTTP-клиент для Java и Kotlin, разработанный компанией Square. Это одна из самых популярных библиотек для работы с REST API в экосистеме Android. Retrofit позволяет разработчикам легко и элегантно выполнять HTTP-запросы к удаленным серверам, автоматически преобразуя JSON-ответы в Kotlin-объекты и наоборот.

Зачем нужен Retrofit?

  • Упрощение работы с API: Вместо написания громоздкого кода с HttpURLConnection или OkHttp, вы определяете интерфейс с аннотациями, и Retrofit сам генерирует реализацию.
  • Автоматическая сериализация/десериализация: Благодаря интеграции с конвертерами (Gson, Moshi, Kotlinx Serialization), Retrofit автоматически преобразует JSON в Kotlin-объекты.
  • Поддержка различных HTTP-методов: GET, POST, PUT, DELETE, PATCH, HEAD и OPTIONS.
  • Управление заголовками и параметрами: Легко добавлять динамические или статические заголовки, query-параметры и path-параметры.
  • Асинхронность: Поддержка корутин Kotlin (suspend функции) и Callback-интерфейсов.
  • Интеграция с OkHttp: Retrofit использует OkHttp как HTTP-движок, что дает доступ к мощным возможностям перехвата запросов (interceptors).

Retrofit идеально подходит для Android-приложений, которые взаимодействуют с RESTful веб-сервисами: от простых погодных приложений до сложных социальных сетей.

Установка Retrofit в проект Kotlin

В отличие от Python (где используется pip), в Kotlin/Android проектах зависимости управляются через Gradle. Добавьте следующие строки в файл build.gradle.kts (или build.gradle) вашего модуля (обычно app):

// build.gradle.kts (Module :app)
dependencies {
    // Основная библиотека Retrofit
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    
    // Конвертер для работы с JSON (Gson)
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    
    // Альтернативный конвертер (Moshi)
    // implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
    
    // Для поддержки корутин (suspend функции)
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
    
    // OkHttp (обычно уже включен, но можно добавить явно)
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}

Важно: После добавления зависимостей нажмите "Sync Now" в Android Studio, чтобы загрузить библиотеки.

Быстрый старт: пример кода

Давайте создадим простое приложение, которое получает список постов с JSONPlaceholder (бесплатный тестовый API).

Шаг 1: Создайте data-класс для ответа

data class Post(
    val userId: Int,
    val id: Int,
    val title: String,
    val body: String
)

Шаг 2: Определите API-интерфейс

interface ApiService {
    @GET("posts")
    suspend fun getPosts(): List<Post>
    
    @GET("posts/{id}")
    suspend fun getPostById(@Path("id") postId: Int): Post
}

Шаг 3: Создайте Retrofit-клиент

object RetrofitClient {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
    
    val instance: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

Шаг 4: Используйте в Activity или ViewModel

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Запускаем корутину
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val posts = RetrofitClient.instance.getPosts()
                withContext(Dispatchers.Main) {
                    // Обновляем UI
                    println("Получено ${posts.size} постов")
                }
            } catch (e: Exception) {
                println("Ошибка: ${e.message}")
            }
        }
    }
}

Основные методы и функции Retrofit

1. @GET — GET-запрос

Описание: Выполняет HTTP GET-запрос для получения данных с сервера.

Параметры: URL-путь (строка), может содержать path-параметры.

@GET("users")
suspend fun getUsers(): List<User>

@GET("users/{id}")
suspend fun getUserById(@Path("id") userId: Int): User

2. @POST — POST-запрос

Описание: Отправляет данные на сервер для создания нового ресурса.

Параметры: URL-путь, тело запроса (@Body).

@POST("posts")
suspend fun createPost(@Body post: Post): Post

3. @PUT — PUT-запрос

Описание: Обновляет существующий ресурс на сервере (полная замена).

Параметры: URL-путь с id, тело запроса.

@PUT("posts/{id}")
suspend fun updatePost(@Path("id") postId: Int, @Body post: Post): Post

4. @DELETE — DELETE-запрос

Описание: Удаляет ресурс на сервере.

Параметры: URL-путь с id.

@DELETE("posts/{id}")
suspend fun deletePost(@Path("id") postId: Int): Response<Unit>

5. @PATCH — PATCH-запрос

Описание: Частичное обновление ресурса (в отличие от PUT, который заменяет весь объект).

Параметры: URL-путь с id, тело запроса с частичными данными.

@PATCH("posts/{id}")
suspend fun patchPost(@Path("id") postId: Int, @Body updates: Map<String, Any>): Post

6. @Query — Query-параметры

Описание: Добавляет параметры запроса в URL (например, ?userId=1).

Параметры: Имя параметра, значение.

@GET("posts")
suspend fun getPostsByUser(@Query("userId") userId: Int): List<Post>

// Множественные параметры
@GET("posts")
suspend fun getFilteredPosts(
    @Query("userId") userId: Int,
    @Query("_sort") sort: String = "id",
    @Query("_order") order: String = "desc"
): List<Post>

7. @Path — Path-параметры

Описание: Заменяет динамические части URL-пути.

Параметры: Имя параметра (должно совпадать с именем в фигурных скобках в URL).

@GET("users/{userId}/posts/{postId}")
suspend fun getUserPost(
    @Path("userId") userId: Int,
    @Path("postId") postId: Int
): Post

8. @Header и @Headers — Заголовки

Описание: Добавляет HTTP-заголовки к запросу. @Header — динамический заголовок, @Headers — статические.

Параметры: Имя и значение заголовка.

// Динамический заголовок
@GET("protected/posts")
suspend fun getProtectedPosts(@Header("Authorization") token: String): List<Post>

// Статические заголовки
@Headers("Cache-Control: max-age=3600", "Accept: application/json")
@GET("posts")
suspend fun getCachedPosts(): List<Post>

9. @Body — Тело запроса

Описание: Передает объект в теле запроса. Автоматически сериализуется в JSON (или другой формат).

Параметры: Любой Kotlin-объект.

data class LoginRequest(val username: String, val password: String)

@POST("auth/login")
suspend fun login(@Body credentials: LoginRequest): Response<LoginResponse>

10. @FormUrlEncoded и @Field — Форма

Описание: Отправляет данные в формате application/x-www-form-urlencoded (как HTML-форма).

Параметры: Пары ключ-значение.

@FormUrlEncoded
@POST("auth/login")
suspend fun loginForm(
    @Field("username") username: String,
    @Field("password") password: String
): Response<LoginResponse>

11. @Multipart и @Part — Многокомпонентные запросы

Описание: Отправляет файлы и данные в формате multipart/form-data (для загрузки файлов).

Параметры: @Part для каждого поля/файла.

@Multipart
@POST("upload")
suspend fun uploadFile(
    @Part("description") description: RequestBody,
    @Part file: MultipartBody.Part
): Response<UploadResponse>

12. @Streaming — Потоковая передача

Описание: Позволяет работать с ResponseBody как с потоком, не загружая его полностью в память. Полезно для больших файлов.

Параметры: Нет.

@Streaming
@GET("large-file.zip")
suspend fun downloadLargeFile(): ResponseBody

Реальный практический пример использования

Давайте создадим полноценный пример: приложение для просмотра погоды с использованием OpenWeatherMap API.

1. Data-классы

data class WeatherResponse(
    val main: Main,
    val weather: List<Weather>,
    val name: String
)

data class Main(
    val temp: Double,
    val feels_like: Double,
    val humidity: Int
)

data class Weather(
    val description: String,
    val icon: String
)

2. API-интерфейс

interface WeatherApiService {
    @GET("weather")
    suspend fun getCurrentWeather(
        @Query("q") cityName: String,
        @Query("appid") apiKey: String,
        @Query("units") units: String = "metric"
    ): WeatherResponse
}

3. Retrofit-клиент с логированием

object WeatherClient {
    private const val BASE_URL = "https://api.openweathermap.org/data/2.5/"
    
    val instance: WeatherApiService by lazy {
        val loggingInterceptor = HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        }
        
        val client = OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .build()
        
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(WeatherApiService::class.java)
    }
}

4. ViewModel для управления состоянием

class WeatherViewModel : ViewModel() {
    private val _weatherState = MutableStateFlow<WeatherUiState>(WeatherUiState.Loading)
    val weatherState: StateFlow<WeatherUiState> = _weatherState.asStateFlow()
    
    fun fetchWeather(city: String) {
        viewModelScope.launch {
            _weatherState.value = WeatherUiState.Loading
            try {
                val response = WeatherClient.instance.getCurrentWeather(
                    cityName = city                    

Рекомендаций