Retrofit

Dart向けのタイプセーフHTTPクライアント生成ライブラリ。Dioベースで、source_genを使用してインターフェース定義から自動的にHTTPクライアント実装を生成。Android RetrofitからインスパイアされたAPI設計により、宣言的で保守性の高いAPI通信を実現。

HTTPクライアントJavaAndroid型安全アノテーションREST

GitHub概要

square/retrofit

A type-safe HTTP client for Android and the JVM

スター43,775
ウォッチ1,547
フォーク7,343
作成日:2010年9月6日
言語:HTML
ライセンス:Apache License 2.0

トピックス

androidjava

スター履歴

square/retrofit Star History
データ取得日時: 2025/10/22 09:55

ライブラリ

Retrofit

概要

Retrofitは「Android/JVM向けの型安全なHTTPクライアント」として開発された、Java/AndroidエコシステムでRESTful API消費のデファクトスタンダードとして確立している高レベルHTTPクライアントライブラリです。「アノテーションベースのAPI定義」を重視して設計され、Javaインターフェースを使用してHTTP APIを宣言的に定義し、実行時に具象実装を自動生成。型安全性、コンパイル時チェック、自動シリアライゼーション、多様な非同期処理モデル、豊富な拡張性により、複雑なWeb API統合を直感的で保守性の高いコードで実現します。

詳細

Retrofit 2025年版(v2.11系)は、Javaエコシステムにおける成熟したHTTP通信ソリューションとして継続的進化を遂げています。OkHttpをベースとした堅牢な実装により、ServiceMethod、RequestFactory、OkHttpCall、CallAdapter、Converterの5つの主要コンポーネントが連携し、インターフェースメソッド呼び出しをHTTPリクエストに変換。アノテーションベースのAPI設計(@GET、@POST、@PUT等)、多様なConverter(Gson、Moshi、Jackson、Protocol Buffers等)、CallAdapter(RxJava、Kotlin Coroutines、CompletableFuture等)、包括的なエラーハンドリング、マルチパート/フォームデータ対応により、現代的なAndroid/Javaアプリケーション開発の要求を満たします。

主な特徴

  • 型安全なAPI定義: コンパイル時型チェックによる高い信頼性とバグ予防
  • アノテーションベース設計: 宣言的で直感的なAPI定義による高い可読性
  • 自動シリアライゼーション: JSON/XML等の自動変換による開発効率向上
  • 多様な非同期モデル: 同期、非同期、RxJava、Kotlin Coroutines対応
  • 豊富な拡張性: Converter/CallAdapterによるカスタマイズ性
  • OkHttp統合: 高性能HTTP処理と接続プーリング最適化

メリット・デメリット

メリット

  • Java/AndroidエコシステムでのRESTクライアントのデファクトスタンダード地位
  • アノテーションベースの宣言的API定義による高い開発効率と可読性
  • 強力な型安全性とコンパイル時検証による実行時エラー大幅削減
  • 豊富なConverter/CallAdapterによる多様なデータ形式・非同期モデル対応
  • 充実したドキュメントと豊富なコミュニティサポート
  • OkHttpベースの高性能ネットワーク処理と詳細設定可能性

デメリット

  • 学習コストと初期設定の複雑さ(アノテーション理解必須)
  • リフレクションベースの実装による実行時オーバーヘッド
  • Converterやライブラリ依存による依存関係の増加
  • 非常に単純なHTTP通信では過度に高機能すぎる場合
  • ProGuard/R8環境での設定複雑性(keep rule必要)
  • Android Runtime制約による一部Java 8機能制限

参考ページ

書き方の例

インストールと基本セットアップ

// build.gradle (Module: app) - 基本設定
dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.11.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.11.0'  // JSON変換用
    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'  // ログ用
}

// マルチパート/ファイルアップロード対応
dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.11.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.11.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.11.0'  // String変換用
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}

// RxJava統合版
dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.11.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava3:2.11.0'
    implementation 'io.reactivex.rxjava3:rxjava:3.1.8'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
}
// 基本的なAPIインターフェース定義
import retrofit2.Call;
import retrofit2.http.*;

// ユーザーデータクラス
public class User {
    public int id;
    public String name;
    public String email;
    public int age;
    public String avatarUrl;
    
    // コンストラクタ、getter/setter省略
}

public class UserCreateRequest {
    public String name;
    public String email;
    public int age;
    
    public UserCreateRequest(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }
}

// API インターフェース定義
public interface UserApiService {
    // GET リクエスト(全ユーザー取得)
    @GET("users")
    Call<List<User>> getUsers();
    
    // GET リクエスト(特定ユーザー取得)
    @GET("users/{id}")
    Call<User> getUser(@Path("id") int userId);
    
    // GET リクエスト(クエリパラメータ付き)
    @GET("users")
    Call<List<User>> getUsersWithQuery(
        @Query("page") int page,
        @Query("limit") int limit,
        @Query("sort") String sort
    );
    
    // POST リクエスト(ユーザー作成)
    @POST("users")
    Call<User> createUser(@Body UserCreateRequest user);
    
    // PUT リクエスト(ユーザー更新)
    @PUT("users/{id}")
    Call<User> updateUser(
        @Path("id") int userId,
        @Body UserCreateRequest user
    );
    
    // DELETE リクエスト
    @DELETE("users/{id}")
    Call<Void> deleteUser(@Path("id") int userId);
    
    // ヘッダー付きリクエスト
    @GET("users/profile")
    Call<User> getProfile(@Header("Authorization") String token);
}

// Retrofit インスタンス作成
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ApiClient {
    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit;
    
    public static Retrofit getRetrofitInstance() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        }
        return retrofit;
    }
    
    public static UserApiService getUserApiService() {
        return getRetrofitInstance().create(UserApiService.class);
    }
}

基本的なAPIコール(同期・非同期)

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.util.Log;

public class UserRepository {
    private UserApiService apiService;
    
    public UserRepository() {
        this.apiService = ApiClient.getUserApiService();
    }
    
    // 同期実行(メインスレッド以外で実行すること)
    public List<User> getUsersSync() {
        try {
            Call<List<User>> call = apiService.getUsers();
            Response<List<User>> response = call.execute();
            
            if (response.isSuccessful()) {
                return response.body();
            } else {
                Log.e("API_ERROR", "Error code: " + response.code());
                return null;
            }
        } catch (IOException e) {
            Log.e("NETWORK_ERROR", "Network error", e);
            return null;
        }
    }
    
    // 非同期実行(推奨)
    public void getUsersAsync(ApiCallback<List<User>> callback) {
        Call<List<User>> call = apiService.getUsers();
        call.enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                if (response.isSuccessful()) {
                    callback.onSuccess(response.body());
                } else {
                    callback.onError("API Error: " + response.code() + " - " + response.message());
                }
            }
            
            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                callback.onError("Network Error: " + t.getMessage());
            }
        });
    }
    
    // 特定ユーザー取得
    public void getUserById(int userId, ApiCallback<User> callback) {
        Call<User> call = apiService.getUser(userId);
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    User user = response.body();
                    if (user != null) {
                        callback.onSuccess(user);
                    } else {
                        callback.onError("User not found");
                    }
                } else {
                    handleErrorResponse(response, callback);
                }
            }
            
            @Override
            public void onFailure(Call<User> call, Throwable t) {
                callback.onError("Network error: " + t.getMessage());
            }
        });
    }
    
    // ユーザー作成
    public void createUser(String name, String email, int age, ApiCallback<User> callback) {
        UserCreateRequest request = new UserCreateRequest(name, email, age);
        Call<User> call = apiService.createUser(request);
        
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    callback.onSuccess(response.body());
                } else {
                    handleErrorResponse(response, callback);
                }
            }
            
            @Override
            public void onFailure(Call<User> call, Throwable t) {
                callback.onError("Create user failed: " + t.getMessage());
            }
        });
    }
    
    // エラーレスポンス処理
    private void handleErrorResponse(Response<?> response, ApiCallback<?> callback) {
        try {
            String errorBody = response.errorBody().string();
            String errorMsg = String.format("HTTP %d: %s - %s", 
                response.code(), response.message(), errorBody);
            callback.onError(errorMsg);
        } catch (IOException e) {
            callback.onError("HTTP " + response.code() + ": " + response.message());
        }
    }
}

// コールバックインターフェース
public interface ApiCallback<T> {
    void onSuccess(T result);
    void onError(String error);
}

// 使用例
public class MainActivity extends AppCompatActivity {
    private UserRepository userRepository;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        userRepository = new UserRepository();
        
        // ユーザー一覧取得
        userRepository.getUsersAsync(new ApiCallback<List<User>>() {
            @Override
            public void onSuccess(List<User> users) {
                Log.d("API_SUCCESS", "取得したユーザー数: " + users.size());
                // UIを更新
                updateUserList(users);
            }
            
            @Override
            public void onError(String error) {
                Log.e("API_ERROR", error);
                // エラー表示
                showError(error);
            }
        });
    }
    
    private void updateUserList(List<User> users) {
        // リストビューやRecyclerViewの更新
    }
    
    private void showError(String error) {
        // エラーダイアログやトーストの表示
        Toast.makeText(this, error, Toast.LENGTH_LONG).show();
    }
}

高度な設定(認証、インターセプター、タイムアウト)

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.util.concurrent.TimeUnit;

public class AdvancedApiClient {
    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit;
    
    // 高度なRetrofitインスタンス作成
    public static Retrofit getAdvancedRetrofitInstance() {
        if (retrofit == null) {
            // HTTP ログインターセプター
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            
            // 認証インターセプター
            Interceptor authInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request originalRequest = chain.request();
                    
                    // 認証トークン取得(SharedPreferencesやSecureStorageから)
                    String token = getAuthToken();
                    
                    if (token != null) {
                        Request authenticatedRequest = originalRequest.newBuilder()
                            .header("Authorization", "Bearer " + token)
                            .header("Accept", "application/json")
                            .header("Content-Type", "application/json")
                            .build();
                        return chain.proceed(authenticatedRequest);
                    }
                    
                    return chain.proceed(originalRequest);
                }
            };
            
            // リトライインターセプター
            Interceptor retryInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Response response = null;
                    IOException exception = null;
                    
                    int maxRetries = 3;
                    for (int i = 0; i < maxRetries; i++) {
                        try {
                            response = chain.proceed(request);
                            if (response.isSuccessful()) {
                                return response;
                            }
                            // サーバーエラーの場合リトライ
                            if (response.code() >= 500) {
                                response.close();
                                Thread.sleep(1000 * (i + 1)); // 指数バックオフ
                                continue;
                            }
                            return response;
                        } catch (IOException e) {
                            exception = e;
                            if (i == maxRetries - 1) break;
                            try {
                                Thread.sleep(1000 * (i + 1));
                            } catch (InterruptedException ie) {
                                Thread.currentThread().interrupt();
                                throw new IOException("Interrupted during retry", ie);
                            }
                        }
                    }
                    
                    if (exception != null) throw exception;
                    return response;
                }
            };
            
            // OkHttpClient設定
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)      // 接続タイムアウト
                .readTimeout(30, TimeUnit.SECONDS)         // 読み取りタイムアウト
                .writeTimeout(30, TimeUnit.SECONDS)        // 書き込みタイムアウト
                .addInterceptor(authInterceptor)           // 認証
                .addInterceptor(retryInterceptor)          // リトライ
                .addInterceptor(loggingInterceptor)        // ログ(デバッグ時のみ)
                .build();
            
            // Retrofit設定
            retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create(createCustomGson()))
                .build();
        }
        return retrofit;
    }
    
    // カスタムGson設定
    private static Gson createCustomGson() {
        return new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .setDateFormat("yyyy-MM-dd HH:mm:ss")
            .excludeFieldsWithoutExposeAnnotation()
            .create();
    }
    
    // 認証トークン取得
    private static String getAuthToken() {
        // SharedPreferencesやSecureStorageから取得
        // 実装は環境に依存
        return "your-auth-token";
    }
}

// SSL証明書ピンニング
public class SSLPinnedApiClient {
    public static Retrofit createSSLPinnedRetrofit() {
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
            .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
            .build();
        
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .certificatePinner(certificatePinner)
            .build();
        
        return new Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    }
}

// 動的ベースURL設定
public interface DynamicApiService {
    @GET
    Call<User> getUser(@Url String fullUrl);
    
    @GET("users/{id}")
    Call<User> getUserWithDynamicBase(@Path("id") int userId);
}

// プロキシ設定
public class ProxyApiClient {
    public static Retrofit createProxyRetrofit() {
        Proxy proxy = new Proxy(Proxy.Type.HTTP, 
            new InetSocketAddress("proxy.example.com", 8080));
        
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .proxy(proxy)
            .build();
        
        return new Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    }
}

ファイルアップロード・マルチパートフォーム

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import java.io.File;

// ファイルアップロード用APIインターフェース
public interface FileUploadService {
    // 単一ファイルアップロード
    @Multipart
    @POST("upload/single")
    Call<UploadResponse> uploadSingleFile(
        @Part("description") RequestBody description,
        @Part MultipartBody.Part file
    );
    
    // 複数ファイルアップロード
    @Multipart
    @POST("upload/multiple")
    Call<UploadResponse> uploadMultipleFiles(
        @Part("title") RequestBody title,
        @Part("category") RequestBody category,
        @Part List<MultipartBody.Part> files
    );
    
    // プロフィール更新(画像+データ)
    @Multipart
    @PUT("users/{id}/profile")
    Call<User> updateProfile(
        @Path("id") int userId,
        @Part("name") RequestBody name,
        @Part("email") RequestBody email,
        @Part MultipartBody.Part avatar
    );
    
    // フォームデータ送信
    @FormUrlEncoded
    @POST("users/register")
    Call<User> registerUser(
        @Field("username") String username,
        @Field("email") String email,
        @Field("password") String password,
        @Field("age") int age
    );
    
    // ファイルダウンロード
    @GET("files/{fileId}/download")
    Call<ResponseBody> downloadFile(@Path("fileId") String fileId);
}

public class UploadResponse {
    public String fileId;
    public String fileName;
    public long fileSize;
    public String downloadUrl;
    public String message;
}

public class FileUploadRepository {
    private FileUploadService uploadService;
    
    public FileUploadRepository() {
        this.uploadService = ApiClient.getRetrofitInstance()
            .create(FileUploadService.class);
    }
    
    // 単一ファイルアップロード
    public void uploadSingleFile(File file, String description, 
                                ApiCallback<UploadResponse> callback) {
        // ファイルをRequestBodyに変換
        RequestBody requestFile = RequestBody.create(
            MediaType.parse("multipart/form-data"), file);
        
        // MultipartBody.Part作成
        MultipartBody.Part filePart = MultipartBody.Part.createFormData(
            "file", file.getName(), requestFile);
        
        // 説明文をRequestBodyに変換
        RequestBody descriptionBody = RequestBody.create(
            MediaType.parse("multipart/form-data"), description);
        
        Call<UploadResponse> call = uploadService.uploadSingleFile(descriptionBody, filePart);
        call.enqueue(new Callback<UploadResponse>() {
            @Override
            public void onResponse(Call<UploadResponse> call, Response<UploadResponse> response) {
                if (response.isSuccessful()) {
                    callback.onSuccess(response.body());
                } else {
                    callback.onError("Upload failed: " + response.code());
                }
            }
            
            @Override
            public void onFailure(Call<UploadResponse> call, Throwable t) {
                callback.onError("Upload error: " + t.getMessage());
            }
        });
    }
    
    // 複数ファイルアップロード
    public void uploadMultipleFiles(List<File> files, String title, String category,
                                   ApiCallback<UploadResponse> callback) {
        List<MultipartBody.Part> fileParts = new ArrayList<>();
        
        for (File file : files) {
            RequestBody requestFile = RequestBody.create(
                MediaType.parse("multipart/form-data"), file);
            MultipartBody.Part filePart = MultipartBody.Part.createFormData(
                "files", file.getName(), requestFile);
            fileParts.add(filePart);
        }
        
        RequestBody titleBody = RequestBody.create(
            MediaType.parse("multipart/form-data"), title);
        RequestBody categoryBody = RequestBody.create(
            MediaType.parse("multipart/form-data"), category);
        
        Call<UploadResponse> call = uploadService.uploadMultipleFiles(
            titleBody, categoryBody, fileParts);
        
        call.enqueue(new Callback<UploadResponse>() {
            @Override
            public void onResponse(Call<UploadResponse> call, Response<UploadResponse> response) {
                if (response.isSuccessful()) {
                    callback.onSuccess(response.body());
                } else {
                    callback.onError("Multiple upload failed: " + response.code());
                }
            }
            
            @Override
            public void onFailure(Call<UploadResponse> call, Throwable t) {
                callback.onError("Multiple upload error: " + t.getMessage());
            }
        });
    }
    
    // プロフィール画像アップロード
    public void updateProfileWithAvatar(int userId, String name, String email, 
                                       File avatarFile, ApiCallback<User> callback) {
        RequestBody nameBody = RequestBody.create(
            MediaType.parse("multipart/form-data"), name);
        RequestBody emailBody = RequestBody.create(
            MediaType.parse("multipart/form-data"), email);
        
        RequestBody avatarRequestBody = RequestBody.create(
            MediaType.parse("image/*"), avatarFile);
        MultipartBody.Part avatarPart = MultipartBody.Part.createFormData(
            "avatar", avatarFile.getName(), avatarRequestBody);
        
        Call<User> call = uploadService.updateProfile(userId, nameBody, emailBody, avatarPart);
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    callback.onSuccess(response.body());
                } else {
                    callback.onError("Profile update failed: " + response.code());
                }
            }
            
            @Override
            public void onFailure(Call<User> call, Throwable t) {
                callback.onError("Profile update error: " + t.getMessage());
            }
        });
    }
    
    // ファイルダウンロード
    public void downloadFile(String fileId, File destinationFile, 
                            DownloadCallback callback) {
        Call<ResponseBody> call = uploadService.downloadFile(fileId);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful()) {
                    // バックグラウンドでファイル保存
                    new Thread(() -> {
                        try {
                            saveFileFromResponseBody(response.body(), destinationFile);
                            callback.onDownloadComplete(destinationFile);
                        } catch (IOException e) {
                            callback.onDownloadError("File save error: " + e.getMessage());
                        }
                    }).start();
                } else {
                    callback.onDownloadError("Download failed: " + response.code());
                }
            }
            
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                callback.onDownloadError("Download error: " + t.getMessage());
            }
        });
    }
    
    private void saveFileFromResponseBody(ResponseBody body, File destinationFile) throws IOException {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        
        try {
            byte[] fileReader = new byte[4096];
            long fileSize = body.contentLength();
            long fileSizeDownloaded = 0;
            
            inputStream = body.byteStream();
            outputStream = new FileOutputStream(destinationFile);
            
            while (true) {
                int read = inputStream.read(fileReader);
                if (read == -1) break;
                
                outputStream.write(fileReader, 0, read);
                fileSizeDownloaded += read;
                
                Log.d("DOWNLOAD", "Downloaded: " + fileSizeDownloaded + " / " + fileSize);
            }
            
            outputStream.flush();
        } finally {
            if (inputStream != null) inputStream.close();
            if (outputStream != null) outputStream.close();
        }
    }
}

public interface DownloadCallback {
    void onDownloadComplete(File file);
    void onDownloadError(String error);
}

エラーハンドリングと詳細レスポンス処理

import retrofit2.HttpException;
import com.google.gson.JsonSyntaxException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

// カスタムエラーレスポンス
public class ApiErrorResponse {
    public int code;
    public String message;
    public String details;
    public List<FieldError> fieldErrors;
    
    public static class FieldError {
        public String field;
        public String message;
    }
}

// エラーハンドリング用ユーティリティ
public class ApiErrorHandler {
    
    public static String handleError(Throwable throwable) {
        if (throwable instanceof HttpException) {
            return handleHttpException((HttpException) throwable);
        } else if (throwable instanceof SocketTimeoutException) {
            return "接続がタイムアウトしました。ネットワーク状況を確認してください。";
        } else if (throwable instanceof UnknownHostException) {
            return "サーバーに接続できません。インターネット接続を確認してください。";
        } else if (throwable instanceof JsonSyntaxException) {
            return "サーバーからの応答形式が正しくありません。";
        } else if (throwable instanceof IOException) {
            return "ネットワークエラーが発生しました: " + throwable.getMessage();
        } else {
            return "予期しないエラーが発生しました: " + throwable.getMessage();
        }
    }
    
    private static String handleHttpException(HttpException exception) {
        int code = exception.code();
        
        try {
            String errorBody = exception.response().errorBody().string();
            Gson gson = new Gson();
            ApiErrorResponse errorResponse = gson.fromJson(errorBody, ApiErrorResponse.class);
            
            if (errorResponse != null && errorResponse.message != null) {
                return errorResponse.message;
            }
        } catch (Exception e) {
            // エラーレスポンスの解析に失敗した場合のフォールバック
        }
        
        switch (code) {
            case 400:
                return "リクエストが不正です。入力内容を確認してください。";
            case 401:
                return "認証が必要です。ログインしてください。";
            case 403:
                return "この操作を実行する権限がありません。";
            case 404:
                return "要求されたリソースが見つかりません。";
            case 409:
                return "データが競合しています。最新の情報を取得してください。";
            case 422:
                return "入力データに問題があります。内容を確認してください。";
            case 429:
                return "リクエスト制限に達しました。しばらく時間をおいて再度お試しください。";
            case 500:
                return "サーバー内部エラーが発生しました。しばらく時間をおいて再度お試しください。";
            case 502:
                return "サーバーが一時的に利用できません。";
            case 503:
                return "サービスが一時的に利用できません。メンテナンス中の可能性があります。";
            default:
                return "HTTP エラー " + code + " が発生しました。";
        }
    }
}

// 詳細なレスポンス処理
public class DetailedApiRepository {
    private UserApiService apiService;
    
    public DetailedApiRepository() {
        this.apiService = ApiClient.getRetrofitInstance().create(UserApiService.class);
    }
    
    // 詳細なレスポンス情報を含むコールバック
    public interface DetailedApiCallback<T> {
        void onSuccess(T result, Response<T> response);
        void onError(String error, int httpCode, Response<T> response);
        void onNetworkError(String error);
    }
    
    public void getUserWithDetailedResponse(int userId, DetailedApiCallback<User> callback) {
        Call<User> call = apiService.getUser(userId);
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    User user = response.body();
                    
                    // レスポンスヘッダーの確認
                    String rateLimit = response.headers().get("X-RateLimit-Remaining");
                    String serverTime = response.headers().get("Date");
                    
                    Log.d("API_INFO", "Rate limit remaining: " + rateLimit);
                    Log.d("API_INFO", "Server time: " + serverTime);
                    Log.d("API_INFO", "Response time: " + (System.currentTimeMillis() - call.request().tag()));
                    
                    callback.onSuccess(user, response);
                } else {
                    // エラーレスポンスの詳細処理
                    try {
                        String errorBody = response.errorBody().string();
                        Log.e("API_ERROR", "Error body: " + errorBody);
                        
                        Gson gson = new Gson();
                        ApiErrorResponse errorResponse = gson.fromJson(errorBody, ApiErrorResponse.class);
                        
                        String errorMessage = (errorResponse != null && errorResponse.message != null) 
                            ? errorResponse.message 
                            : ApiErrorHandler.handleError(new HttpException(response));
                        
                        callback.onError(errorMessage, response.code(), response);
                    } catch (IOException e) {
                        callback.onError("エラーレスポンスの解析に失敗しました", response.code(), response);
                    }
                }
            }
            
            @Override
            public void onFailure(Call<User> call, Throwable t) {
                String errorMessage = ApiErrorHandler.handleError(t);
                callback.onNetworkError(errorMessage);
            }
        });
    }
    
    // キャンセル可能なAPIコール
    public Call<List<User>> getUsersWithCancellation(ApiCallback<List<User>> callback) {
        Call<List<User>> call = apiService.getUsers();
        
        call.enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                if (!call.isCanceled()) {
                    if (response.isSuccessful()) {
                        callback.onSuccess(response.body());
                    } else {
                        callback.onError("API Error: " + response.code());
                    }
                }
            }
            
            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                if (!call.isCanceled()) {
                    callback.onError(ApiErrorHandler.handleError(t));
                }
            }
        });
        
        return call;  // 呼び出し元でキャンセル可能
    }
}

// 使用例:キャンセル機能付きAPI呼び出し
public class CancellableApiActivity extends AppCompatActivity {
    private Call<List<User>> currentCall;
    private DetailedApiRepository repository;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        repository = new DetailedApiRepository();
        
        // キャンセル可能なAPI呼び出し
        currentCall = repository.getUsersWithCancellation(new ApiCallback<List<User>>() {
            @Override
            public void onSuccess(List<User> users) {
                // UI更新
                updateUserList(users);
            }
            
            @Override
            public void onError(String error) {
                // エラー表示
                showError(error);
            }
        });
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // アクティビティ破棄時にAPIコールをキャンセル
        if (currentCall != null && !currentCall.isCanceled()) {
            currentCall.cancel();
        }
    }
    
    private void updateUserList(List<User> users) {
        // リスト更新処理
    }
    
    private void showError(String error) {
        Toast.makeText(this, error, Toast.LENGTH_LONG).show();
    }
}

RxJava/Kotlin Coroutines統合

// RxJava統合
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.schedulers.Schedulers;

// RxJava用APIインターフェース
public interface RxUserApiService {
    @GET("users")
    Observable<List<User>> getUsers();
    
    @GET("users/{id}")
    Single<User> getUser(@Path("id") int userId);
    
    @POST("users")
    Single<User> createUser(@Body UserCreateRequest user);
}

// RxJava対応Retrofitクライアント
public class RxApiClient {
    private static Retrofit retrofit;
    
    public static Retrofit getRxRetrofitInstance() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .build();
        }
        return retrofit;
    }
    
    public static RxUserApiService getRxUserApiService() {
        return getRxRetrofitInstance().create(RxUserApiService.class);
    }
}

public class RxUserRepository {
    private RxUserApiService apiService;
    
    public RxUserRepository() {
        this.apiService = RxApiClient.getRxUserApiService();
    }
    
    // RxJava を使用したAPI呼び出し
    public void loadUsersWithRx() {
        apiService.getUsers()
            .subscribeOn(Schedulers.io())                    // バックグラウンドスレッドで実行
            .observeOn(AndroidSchedulers.mainThread())       // メインスレッドで結果を受け取る
            .subscribe(
                users -> {
                    // 成功時の処理
                    Log.d("RX_SUCCESS", "取得したユーザー数: " + users.size());
                },
                throwable -> {
                    // エラー時の処理
                    String error = ApiErrorHandler.handleError(throwable);
                    Log.e("RX_ERROR", error);
                }
            );
    }
    
    // 複数API呼び出しの組み合わせ
    public void loadUserWithDetails(int userId) {
        Single.zip(
            apiService.getUser(userId),
            apiService.getUserPosts(userId),
            apiService.getUserFollowers(userId),
            (user, posts, followers) -> {
                // 3つのAPIレスポンスを組み合わせ
                UserWithDetails userDetails = new UserWithDetails();
                userDetails.user = user;
                userDetails.posts = posts;
                userDetails.followers = followers;
                return userDetails;
            }
        )
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            userDetails -> {
                // 統合されたデータの処理
                Log.d("RX_SUCCESS", "ユーザー詳細取得完了");
            },
            throwable -> {
                Log.e("RX_ERROR", ApiErrorHandler.handleError(throwable));
            }
        );
    }
}
// Kotlin Coroutines統合
import kotlinx.coroutines.*

// Kotlin Suspend Function対応APIインターフェース
interface CoroutineUserApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
    
    @GET("users/{id}")
    suspend fun getUser(@Path("id") userId: Int): User
    
    @POST("users")
    suspend fun createUser(@Body user: UserCreateRequest): User
    
    @PUT("users/{id}")
    suspend fun updateUser(@Path("id") userId: Int, @Body user: UserCreateRequest): User
    
    @DELETE("users/{id}")
    suspend fun deleteUser(@Path("id") userId: Int): Response<Void>
}

class CoroutineUserRepository {
    private val apiService = ApiClient.getRetrofitInstance()
        .create(CoroutineUserApiService::class.java)
    
    // Coroutineを使用したAPI呼び出し
    suspend fun getUsers(): Result<List<User>> {
        return try {
            val users = apiService.getUsers()
            Result.success(users)
        } catch (e: Exception) {
            val errorMessage = ApiErrorHandler.handleError(e)
            Result.failure(Exception(errorMessage))
        }
    }
    
    suspend fun getUserById(userId: Int): Result<User> {
        return try {
            val user = apiService.getUser(userId)
            Result.success(user)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    // 複数のAPI呼び出しを並行実行
    suspend fun getUserWithDetailsParallel(userId: Int): Result<UserWithDetails> {
        return try {
            val userDeferred = async { apiService.getUser(userId) }
            val postsDeferred = async { apiService.getUserPosts(userId) }
            val followersDeferred = async { apiService.getUserFollowers(userId) }
            
            val user = userDeferred.await()
            val posts = postsDeferred.await()
            val followers = followersDeferred.await()
            
            val userDetails = UserWithDetails(user, posts, followers)
            Result.success(userDetails)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

// Activity/FragmentでのCoroutine使用例
class CoroutineActivity : AppCompatActivity() {
    private val repository = CoroutineUserRepository()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ライフサイクルスコープでCoroutine実行
        lifecycleScope.launch {
            loadUsers()
        }
    }
    
    private suspend fun loadUsers() {
        try {
            // ローディング表示
            showLoading(true)
            
            // API呼び出し
            val result = repository.getUsers()
            
            result.fold(
                onSuccess = { users ->
                    // 成功時の処理
                    updateUserList(users)
                    showLoading(false)
                },
                onFailure = { exception ->
                    // エラー時の処理
                    showError(exception.message ?: "Unknown error")
                    showLoading(false)
                }
            )
        } catch (e: Exception) {
            showError("Unexpected error: ${e.message}")
            showLoading(false)
        }
    }
    
    private fun updateUserList(users: List<User>) {
        // UI更新処理
    }
    
    private fun showLoading(show: Boolean) {
        // ローディング表示/非表示
    }
    
    private fun showError(message: String) {
        // エラー表示
    }
}