Retrofit

Retrofit — це потужна бібліотека для Android і Java, яка спрощує взаємодію з REST API. Вона дозволяє вам легко працювати з HTTP-запитами, абстрагуючи низькорівневі деталі. Retrofit підтримує автоматичне перетворення JSON у Java-об'єкти за допомогою таких бібліотек, як Moshi, Gson або Jackson.

У цій статті ми розглянемо основи використання Retrofit у Java, найкращі практики та кроки для налаштування і створення запитів до REST API.

Залежності для Retrofit

Перед тим як почати, потрібно додати необхідні залежності у вашому проекті.

1. Додавання залежностей до build.gradle

У вашому файлі build.gradle додайте наступні залежності:

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0' // Основна бібліотека Retrofit
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Конвертер для Gson
    implementation 'com.squareup.okhttp3:okhttp:4.9.0' // OkHttp для роботи з HTTP
    implementation 'com.squareup.moshi:moshi:1.12.0' // Можна використовувати Moshi для серіалізації
}

Налаштування Retrofit

1. Створення інтерфейсу API

Перше, що потрібно зробити, це визначити інтерфейс, який буде описувати ваші HTTP-запити. Для кожного ендпоінта API ви створюєте відповідний метод, який позначається за допомогою анотацій, таких як @GET, @POST, @PUT тощо.

Ось приклад:

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface ApiService {
    @GET("posts")
    Call<List<Post>> getPosts();

    @GET("posts")
    Call<List<Post>> getPostsByUserId(@Query("userId") int userId);
}

2. Створення Retrofit об'єкта

Далі необхідно налаштувати Retrofit, вказавши базовий URL для вашого API та конвертер для обробки JSON. Використаємо Gson для конвертації JSON у Java-об'єкти:

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {
    private static Retrofit retrofit;

    public static Retrofit getClient() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl("https://jsonplaceholder.typicode.com/") // Базовий URL API
                    .addConverterFactory(GsonConverterFactory.create()) // Додаємо конвертер Gson
                    .build();
        }
        return retrofit;
    }
}

3. Використання Retrofit для виконання запитів

Тепер ми можемо використовувати Retrofit для виконання запитів до API. Ось приклад того, як отримати список постів:

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class Main {
    public static void main(String[] args) {
        // Отримуємо інтерфейс API
        ApiService apiService = RetrofitClient.getClient().create(ApiService.class);

        // Виконуємо асинхронний запит для отримання постів
        Call<List<Post>> call = apiService.getPosts();
        call.enqueue(new Callback<List<Post>>() {
            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
                if (response.isSuccessful()) {
                    List<Post> posts = response.body();
                    // Обробляємо список постів
                    for (Post post : posts) {
                        System.out.println(post.getTitle());
                    }
                } else {
                    System.out.println("Запит не був успішним");
                }
            }

            @Override
            public void onFailure(Call<List<Post>> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }
}

4. Синхронний запит

Якщо вам потрібно виконати запит синхронно (наприклад, в фоновому потоці), ви можете викликати метод execute():

try {
    Response<List<Post>> response = call.execute();
    if (response.isSuccessful()) {
        List<Post> posts = response.body();
        for (Post post : posts) {
            System.out.println(post.getTitle());
        }
    } else {
        System.out.println("Запит не був успішним");
    }
} catch (IOException e) {
    e.printStackTrace();
}

5. Моделювання відповіді

Ваші відповіді від API можуть бути різними. У Retrofit для обробки відповіді використовується Java-класи. Наприклад, для API https://jsonplaceholder.typicode.com/posts ви можете створити клас Post:

public class Post {
    private int userId;
    private int id;
    private String title;
    private String body;

    // Гетери та сетери
    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

Використання Retrofit для CRUD-операцій з JsonPlaceholder

Додаємо необхідні залежності в ваш файл build.gradle:

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0' // Основна бібліотека Retrofit
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Конвертер для Gson
    implementation 'com.squareup.okhttp3:okhttp:4.9.0' // OkHttp для роботи з HTTP
    implementation 'com.squareup.moshi:moshi:1.12.0' // Moshi для серіалізації (опційно)
}

Структура проекту

  1. Моделі — клас, який описує структуру поста.
  2. API інтерфейс — визначення HTTP-запитів.
  3. Реалізація Retrofit — налаштування Retrofit.
  4. Діяльність або ViewModel — обробка запитів і відповіді.

1. Створення моделі даних (Post.java)

Ми створимо клас Post, що відображає дані поста.

public class Post {
    private int userId;
    private int id;
    private String title;
    private String body;

    // Гетери та сетери
    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

2. Створення інтерфейсу API (ApiService.java)

Визначаємо інтерфейс для всіх CRUD-операцій:

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.PUT;
import retrofit2.http.POST;
import retrofit2.http.Path;

import java.util.List;

public interface ApiService {

    // Отримати список всіх постів
    @GET("posts")
    Call<List<Post>> getPosts();

    // Отримати пост за ID
    @GET("posts/{id}")
    Call<Post> getPostById(@Path("id") int id);

    // Створити новий пост
    @POST("posts")
    Call<Post> createPost(@Body Post post);

    // Оновити існуючий пост
    @PUT("posts/{id}")
    Call<Post> updatePost(@Path("id") int id, @Body Post post);

    // Видалити пост
    @DELETE("posts/{id}")
    Call<Void> deletePost(@Path("id") int id);
}

3. Налаштування Retrofit (RetrofitClient.java)

Тепер налаштовуємо Retrofit:

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {
    private static Retrofit retrofit;
    private static final String BASE_URL = "https://jsonplaceholder.typicode.com/";

    public static Retrofit getClient() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create()) // Використовуємо Gson для конвертації
                    .build();
        }
        return retrofit;
    }
}

4. Створення класу для роботи з API (Main.java)

Давайте створимо клас, який буде використовувати інтерфейс ApiService для виконання CRUD-операцій:

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

import java.io.IOException;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        ApiService apiService = RetrofitClient.getClient().create(ApiService.class);

        // Операція GET: отримати всі пости
        getAllPosts(apiService);

        // Операція GET: отримати пост за ID
        getPostById(apiService, 1);

        // Операція POST: створити новий пост
        createPost(apiService);

        // Операція PUT: оновити пост
        updatePost(apiService, 1);

        // Операція DELETE: видалити пост
        deletePost(apiService, 1);
    }

    // Отримати всі пости
    private static void getAllPosts(ApiService apiService) {
        Call<List<Post>> call = apiService.getPosts();
        call.enqueue(new Callback<List<Post>>() {
            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
                if (response.isSuccessful()) {
                    List<Post> posts = response.body();
                    posts.forEach(post -> System.out.println(post.getTitle()));
                } else {
                    System.out.println("Запит не успішний!");
                }
            }

            @Override
            public void onFailure(Call<List<Post>> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

    // Отримати пост за ID
    private static void getPostById(ApiService apiService, int postId) {
        Call<Post> call = apiService.getPostById(postId);
        call.enqueue(new Callback<Post>() {
            @Override
            public void onResponse(Call<Post> call, Response<Post> response) {
                if (response.isSuccessful()) {
                    Post post = response.body();
                    System.out.println("Post Title: " + post.getTitle());
                } else {
                    System.out.println("Запит не успішний!");
                }
            }

            @Override
            public void onFailure(Call<Post> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

    // Створити новий пост
    private static void createPost(ApiService apiService) {
        Post post = new Post();
        post.setUserId(1);
        post.setTitle("New Post Title");
        post.setBody("This is the body of the new post.");

        Call<Post> call = apiService.createPost(post);
        call.enqueue(new Callback<Post>() {
            @Override
            public void onResponse(Call<Post> call, Response<Post> response) {
                if (response.isSuccessful()) {
                    Post createdPost = response.body();
                    System.out.println("Created Post: " + createdPost.getTitle());
                } else {
                    System.out.println("Запит не успішний!");
                }
            }

            @Override
            public void onFailure(Call<Post> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

    // Оновити пост
    private static void updatePost(ApiService apiService, int postId) {
        Post post = new Post();
        post.setTitle("Updated Post Title");
        post.setBody("This is the updated body.");

        Call<Post> call = apiService.updatePost(postId, post);
        call.enqueue(new Callback<Post>() {
            @Override
            public void onResponse(Call<Post> call, Response<Post> response) {
                if (response.isSuccessful()) {
                    Post updatedPost = response.body();
                    System.out.println("Updated Post: " + updatedPost.getTitle());
                } else {
                    System.out.println("Запит не успішний!");
                }
            }

            @Override
            public void onFailure(Call<Post> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

    // Видалити пост
    private static void deletePost(ApiService apiService, int postId) {
        Call<Void> call = apiService.deletePost(postId);
        call.enqueue(new Callback<Void>() {
            @Override
            public void onResponse(Call<Void> call, Response<Void> response) {
                if (response.isSuccessful()) {
                    System.out.println("Post deleted successfully");
                } else {
                    System.out.println("Запит не успішний!");
                }
            }

            @Override
            public void onFailure(Call<Void> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }
}
:video-player{src="https://www.youtube.com/watch?v=GPP4hOTthRg"}