Retrofit — to typowany klient HTTP dla Androida i Kotlin, opracowany przez firmę Square. Biblioteka pozwala przekształcić REST API w interfejs w języku Java lub Kotlin za pomocą adnotacji. Według danych Square, 2025, Retrofit jest używany w tysiącach aplikacji jako standardowe narzędzie do pracy z żądaniami HTTP.
Najważniejsze
Retrofit — to biblioteka do typowanej interakcji z REST API na platformie Android, opracowana przez firmę Square. Zapewnia deklaratywny sposób opisywania żądań HTTP poprzez interfejsy Java lub Kotlin z adnotacjami, całkowicie uwalniając programistę od ręcznego parsowania JSON i zarządzania połączeniami HTTP.
Biblioteka pojawiła się w 2013 roku jako alternatywa dla nieporęcznych rozwiązań takich jak AsyncTask i HttpURLConnection. Do 2025 roku Retrofit pozostaje standardem de facto dla komunikacji sieciowej w aplikacjach Android dzięki prostocie i bezpieczeństwu typów. Według ankiety JetBrains Developer Ecosystem 2024, Retrofit jest używany przez ponad 65% programistów Android w projektach komercyjnych.
Kluczowa różnica między Retrofit a analogami — deklaratywne podejście: programista opisuje co zrobić (jaki endpoint wywołać, jakie parametry przekazać), a nie jak zrobić (jak otworzyć połączenie, jak odczytać InputStream, jak sparsować JSON). Zmniejsza to ilość kodu boilerplate o 60–70% w porównaniu z ręcznym użyciem HttpURLConnection.
Zasada działania Retrofit opiera się na dynamicznych proxy Java. Gdy programista wywołuje metodę interfejsu oznaczonego adnotacjami, Retrofit przez mechanizm Proxy.newProxyInstance przechwytuje wywołanie i przekształca je w żądanie HTTP. Cały proces odbywa się w runtime bez generowania kodu na etapie kompilacji.
Podczas tworzenia instancji Retrofit.Builder określa się bazowy URL i fabrykę konwerterów. Builder konfiguruje OkHttpClient — ustawia timeouty, interceptory, pulę połączeń i pamięć podręczną. Metoda create(Class) generuje implementację interfejsu, zwracając obiekt proxy, który można wywoływać jak zwykłą klasę.
Łańcuch wykonania żądania wygląda następująco: adnotacje pobierają metodę HTTP, parametry są podstawiane do URL lub treści żądania, konwerter serializuje treść, OkHttp wykonuje żądanie, konwerter deserializuje odpowiedź, wynik jest zwracany w określonym typie. Każdy etap jest izolowany i może być zastąpiony własną implementacją, na przykład podmiana OkHttpClient na MockWebServer do testowania lub zmiana konwertera przy zmianie API.
Ważna cecha — Retrofit nie obsługuje bezpośrednio przesyłania strumieniowego danych. Do strumieniowania używa się OkHttp ResponseBody jako typu zwracanego metody interfejsu. Retrofit również nie zarządza automatycznie anulowaniem żądań — do anulowania należy zachować referencję do Call i wywołać cancel(). W Kotlin z funkcjami suspend anulowanie żądania następuje automatycznie przy anulowaniu nadrzędnej korutyny.
Call<T> — to obiekt reprezentujący jedno żądanie HTTP. Po wykonaniu (execute lub enqueue) Call nie może być ponownie użyty — do ponownego żądania należy utworzyć nowy Call przez wywołanie metody interfejsu. Chroni to przed przypadkowym wysłaniem tego samego żądania dwukrotnie, co mogłoby prowadzić do duplikowania operacji na serwerze.
W Kotlin zamiast Call używa się funkcji suspend, które automatycznie zarządzają cyklem życia żądania. Retrofit sam przełącza wykonanie na Dispatchers.IO i zwraca wynik do korutyny. Skraca to kod o 30–40% w porównaniu z wersją na Call i Callback.
Adnotacje — to główny mechanizm konfiguracji żądań HTTP w Retrofit. Każda adnotacja odpowiada standardowej metodzie HTTP i przyjmuje względną ścieżkę do endpointu. Retrofit obsługuje GET, POST, PUT, DELETE, PATCH, HEAD i OPTIONS.
| Adnotacja | Metoda HTTP | Przeznaczenie |
|---|---|---|
| @GET | GET | Pobieranie danych z serwera |
| @POST | POST | Tworzenie nowego zasobu |
| @PUT | PUT | Pełna aktualizacja zasobu |
| @DELETE | DELETE | Usuwanie zasobu |
| @PATCH | PATCH | Częściowa aktualizacja zasobu |
@Path podstawia wartość w segmencie URL: @Path(id) Int id zastępuje {id} w ścieżce. @Query dodaje parametr query: @Query(page) Int page zamienia się w ?page=5. @Body przekazuje obiekt w treści żądania z automatyczną serializacją przez wybrany konwerter. @Header i @Headers zarządzają nagłówkami HTTP — statycznymi lub dynamicznymi.
Łącząc te adnotacje, można opisać dowolny endpoint REST. Na przykład, dla endpointu POST /api/users/{id}/posts?limit=10 potrzebne będą @POST, @Path dla id, @Query dla limit i @Body dla przesyłanego obiektu. Retrofit automatycznie złoży poprawne żądanie HTTP. Dodatkowo obsługiwane są @Url (dynamiczny URL), @Field (form-encoded body), @Part i @PartMap dla żądań multipart z plikami.
Rozważmy praktyczny przykład — interfejs dla API GitHub. Tworzy się interfejs Kotlin z metodą pobierania listy repozytoriów. Data class Repo opisuje strukturę odpowiedzi JSON.
data class Repo(
val name: String,
val description: String?,
val stargazersCount: Int,
val forksCount: Int
)
interface GitHubApi {
@GET("users/{user}/repos")
suspend fun getRepos(
@Path("user") user: String,
@Query("sort") sort: String = "updated"
): List<Repo>
}
Po opisaniu interfejsu tworzy się instancję Retrofit przez Builder. Bazowy URL, konwerter i OkHttpClient są konfigurowane raz i ponownie używane przez wstrzykiwanie zależności.
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build())
.build()
val api = retrofit.create(GitHubApi::class.java)
Do elastycznej obsługi statusów HTTP użyj opakowania Response<T>. Daje ono dostęp do kodu odpowiedzi, nagłówków i treści, nie wyrzucając wyjątku przy błędach 4xx i 5xx. Pozwala to obsługiwać 404 i 500 bez try-catch.
interface GitHubApi {
@GET("users/{user}/repos")
suspend fun getRepos(
@Path("user") user: String
): Response<List<Repo>>
}
val response = api.getRepos("octocat")
if (response.isSuccessful) {
println(response.body()?.size)
} else {
Log.e("API", "Błąd: ${response.code()}")
}
Konwertery — to komponenty Retrofit odpowiedzialne za przekształcanie obiektów w treść HTTP i odwrotnie. Retrofit nie wbudowuje serializacji w rdzeń — zamiast tego stosuje podejście modułowe przez Converter.Factory, pozwalające podłączyć dowolną bibliotekę serializacji.
Najpopularniejszy konwerter — GsonConverterFactory od Google na bazie biblioteki Gson. Nadaje się do większości projektów, obsługuje niestandardowe TypeAdapter i JsonDeserializer. Jednak Gson używa refleksji i nie uwzględnia null safety Kotlin, co może prowadzić do NPE przy nieoczekiwanych polach null.
Alternatywa — MoshiConverterFactory od Square: bardziej rygorystyczny względem typów, z lepszą obsługą Kotlin (null safety, default values) i bez refleksji. Dla projektów w czystym Kotlin optymalny jest Kotlinx Serialization Converter, działający na adnotacjach @Serializable na etapie kompilacji. Nie używa refleksji, obsługuje sealed class, default values i wieloplatformowość.
Wybór konwertera wpływa na wydajność i bezpieczeństwo typów. Gson bez własnej konfiguracji może deserializować null w pole non-null Kotlin, powodując NPE przy odczycie. Moshi rozwiązuje ten problem przez adnotację @Json(name) i failOnUnknown. Kotlinx Serialization jest najbezpieczniejszy — generuje kod na etapie kompilacji, całkowicie eliminując błędy typów w runtime.
Brak obsługi błędów HTTP w funkcjach suspend — najczęstszy problem. Jeśli serwer zwróci 4xx lub 5xx, Retrofit wyrzuca HttpException. Bez try-catch aplikacja zakończy się awaryjnie. Użycie Response<T> jako typu zwracanego rozwiązuje ten problem, pozwalając sprawdzać isSuccessful przed dostępem do body.
Nieprawidłowa konfiguracja pamięci podręcznej prowadzi do nadmiernego ruchu. Retrofit nie buforuje odpowiedzi samodzielnie — to zadanie rozwiązuje OkHttpClient przez Cache. Bez pamięci podręcznej każde żądanie jest wykonywane w całości, nawet gdy dane się nie zmieniły. Dodanie Cache o rozmiarze 10 MB w OkHttpClient zmniejsza ruch o 40–60% przy powtarzających się żądaniach tych samych informacji.
Tworzenie Retrofit dla każdego żądania — częsty błąd początkujących. Retrofit.Builder to operacja zasobożerna, obejmująca generowanie klas proxy w runtime. Prawidłowa praktyka — utworzyć jedną instancję Retrofit i używać jej ponownie przez frameworki DI. Hilt, Koin lub Dagger zapewniają instancję singleton Retrofit dla całej aplikacji, co oszczędza pamięć i przyspiesza żądania.
Ignorowanie Interceptor do autoryzacji — czwarty problem. Zamiast ręcznego dodawania nagłówka Authorization w każdym wywołaniu skonfiguruj globalny Interceptor w OkHttpClient. Interceptor przechwytuje każde żądanie, dodaje token Bearer, a Authenticator obsługuje odpowiedź 401, odświeżając token i powtarzając żądanie automatycznie. To centralizuje logikę uwierzytelniania.
Często zadawane pytania
Retrofit — to nadbudowa nad OkHttp, zapewniająca deklaratywne API przez adnotacje. OkHttp — niskopoziomowy klient HTTP pracujący bezpośrednio z Request i Response. Retrofit upraszcza typizację, serializację i obsługę odpowiedzi, używając OkHttp jako transportu.
Dla projektów Java — GsonConverterFactory. Dla Kotlin z Moshi — MoshiConverterFactory (bezpieczniejszy pod względem typów). Optymalny wybór dla czystego Kotlin — Kotlinx Serialization Converter. Działa bez refleksji, obsługuje sealed class i default values.
Tak, od wersji 2.6.0 Retrofit obsługuje funkcje suspend. Zadeklaruj metodę jako suspend, a Retrofit wykona żądanie na Dispatchers.IO, zwracając wynik do korutyny. Nie trzeba używać Call i enqueue — kod staje się sekwencyjny.
Autoryzacja jest dodawana przez Interceptor OkHttp. W intercept() dodaj nagłówek Authorization. Do dynamicznego tokenu użyj Authenticator OkHttp — przechwytuje on odpowiedź 401 i automatycznie odświeża token, powtarzając żądanie z nowym nagłówkiem.
Nie można — Retrofit zawsze używa OkHttp jako warstwy transportowej. OkHttpClient jest przekazywany przez Builder.client() i zarządza timeoutami, interceptorami, buforowaniem i pulą połączeń. Bez OkHttp Retrofit nie będzie mógł wykonać żadnego żądania.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również