๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Retrofit2] Retrofit2์—์„œ API ํ˜ธ์ถœ ์‹œ ๊ณตํ†ต ํ—ค๋” ๊ฐ’ ์ถ”๊ฐ€ ๋ฐฉ๋ฒ•

์ถœ์ฒ˜

ChatGPT


 

๋ฐฉ๋ฒ•

  1. Interceptor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณตํ†ต ํ•ด๋” ์ถ”๊ฐ€
  2. '@Header' ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ
  3. '@Headers' ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ
  4. OkHttp3 Authenticator ์‚ฌ์šฉ (ํ† ํฐ ์ž๋™ ๊ฐฑ์‹ )

 

1. Interceptor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณตํ†ต ํ—ค๋” ์ถ”๊ฐ€

Interceptor๋Š” ๋ชจ๋“  ๋„คํŠธ์›Œํฌ ์š”์ฒญ์— ๊ณตํ†ต์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ณตํ†ต ํ—ค๋” ๊ฐ’์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

Interceptor๋กœ ๊ณตํ†ต ํ—ค๋” ์ถ”๊ฐ€ํ•˜๊ธฐ

์žฅ์ 

  • ์ฝ”๋“œ์˜ ๋ฐ˜๋ณต์„ ์ค„์—ฌ์ฃผ๊ณ , ๋ชจ๋“  ์š”์ฒญ์— ์ž๋™์œผ๋กœ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ๋ณด์•ˆ ํ† ํฐ๊ณผ ๊ฐ™์€ ๊ณตํ†ต ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.

 

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import java.io.IOException;

public class ApiClient {

    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            // Interceptor ์„ค์ •
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(new Interceptor() {
                        @Override
                        public Response intercept(Chain chain) throws IOException {
                            Request original = chain.request();
                            Request request = original.newBuilder()
                                    .header("Authorization", "Bearer YOUR_TOKEN_HERE")  // ๊ณตํ†ต ํ—ค๋” ์ถ”๊ฐ€
                                    .header("Content-Type", "application/json")
                                    .method(original.method(), original.body())
                                    .build();
                            return chain.proceed(request);
                        }
                    })
                    .build();

            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

 

์„ค๋ช…

 

  • OkHttpClient: OkHttp ํด๋ผ์ด์–ธํŠธ์— Interceptor๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ชจ๋“  ์š”์ฒญ์— ๊ณตํ†ต ํ—ค๋”๋ฅผ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • header(): ์š”์ฒญ์— ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • chain.proceed(request): ์š”์ฒญ์„ ๊ณ„์† ์ง„ํ–‰ํ•œ๋‹ค.

2. '@Header' ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ

'@Header' ์–ด๋…ธํ…Œ์ด์…˜์€ ํŠน์ • ์š”์ฒญ์—๋งŒ ํ—ค๋”๋ฅผ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ๋งค๋ฒˆ ๋‹ค๋ฅธ ํ—ค๋” ๊ฐ’์„ ๋„ฃ๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•˜๋‹ค.

@Header ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

์žฅ์ 

  • ์š”์ฒญ๋งˆ๋‹ค ๋‹ค๋ฅธ ํ—ค๋” ๊ฐ’์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Path;

public interface ApiService {

    // ๋™์ ์œผ๋กœ Authorization ํ—ค๋” ์ถ”๊ฐ€
    @GET("users/{id}")
    Call<User> getUserById(@Path("id") int userId, @Header("Authorization") String token);

    // ๋™์ ์œผ๋กœ Content-Type ํ—ค๋” ์ถ”๊ฐ€
    @GET("users/{id}")
    Call<User> getUserByIdWithContentType(@Path("id") int userId, @Header("Content-Type") String contentType);
}

 

 

์„ค๋ช…

  • @Header("Authorization"): ๋ฉ”์†Œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Authorization ํ—ค๋” ๊ฐ’์„ ์ „๋‹ฌํ•œ๋‹ค.
  • @Header("Content-Type"): Content-Type ํ—ค๋”๋ฅผ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์‹œ์— ์ „๋‹ฌํ•œ๋‹ค.

์‚ฌ์šฉ ์˜ˆ์‹œ

ApiService apiService = retrofit.create(ApiService.class);

Call<User> call = apiService.getUserById(1, "Bearer YOUR_TOKEN_HERE");
call.enqueue(new Callback<User>() {
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        if (response.isSuccessful()) {
            User user = response.body();
            // ์‚ฌ์šฉ์ž ์ •๋ณด ์ฒ˜๋ฆฌ
        }
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
    }
});

 

3. '@Headers' ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ

'@Headers' ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • API ์š”์ฒญ์— ๋Œ€ํ•ด ์ •์ ์ธ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ํŠน์ • ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•ด ํ•ญ์ƒ ์ผ์ •ํ•œ ํ—ค๋”๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

@Headers ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

์žฅ์ 

  • ํŠน์ • ์š”์ฒญ์— ๋Œ€ํ•ด ๊ณ ์ •๋œ ํ—ค๋” ๊ฐ’์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.\
public interface ApiService {

    // ๊ณ ์ •๋œ ํ—ค๋” ์ถ”๊ฐ€
    @Headers({
        "Authorization: Bearer YOUR_TOKEN_HERE",
        "Content-Type: application/json"
    })
    @GET("users/{id}")
    Call<User> getUserById(@Path("id") int userId);
}

 

์„ค๋ช…

  • @Headers: ํ—ค๋” ์ •๋ณด๋ฅผ ๊ณ ์ •์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜์—ฌ ํŠน์ • ์š”์ฒญ์— ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ๋งค๋ฒˆ ๊ฐ™์€ ํ—ค๋”๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜๋‹ค.

4. OkHttp3 Authenticator ์‚ฌ์šฉ (ํ† ํฐ ์ž๋™ ๊ฐฑ์‹ )

์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์ด ํ•„์š”ํ•œ API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ํ† ํฐ์„ ์ž๋™์œผ๋กœ ๊ฐฑ์‹ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, "Authenticator"๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ธ์ฆ ์‹คํŒจ ์‹œ ์ž๋™์œผ๋กœ ์ƒˆ๋กœ์šด ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›๊ณ  ์š”์ฒญ์„ ์žฌ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค.

Authenticator ์‚ฌ์šฉ ์˜ˆ์‹œ

์žฅ์ 

  • ์ž๋™์œผ๋กœ ํ† ํฐ์„ ์ƒ์‹ ํ•˜๊ณ , ์š”์ฒญ์„ ์žฌ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค.
import okhttp3.Authenticator;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
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 = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            OkHttpClient client = new OkHttpClient.Builder()
                    .authenticator(new Authenticator() {
                        @Override
                        public Request authenticate(Route route, Response response) {
                            // ์ƒˆ๋กœ์šด ํ† ํฐ ๋ฐœ๊ธ‰ ๋กœ์ง (์˜ˆ์‹œ)
                            String newAccessToken = getNewAccessToken();

                            // ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๊ธฐ์กด ์š”์ฒญ๊ณผ ํ•จ๊ป˜ ์ƒˆ ํ† ํฐ์œผ๋กœ ์ƒ์„ฑ
                            return response.request().newBuilder()
                                    .header("Authorization", "Bearer " + newAccessToken)
                                    .build();
                        }
                    })
                    .build();

            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }

    private static String getNewAccessToken() {
        // ์ƒˆ๋กœ์šด ์•ก์„ธ์Šค ํ† ํฐ ๋ฐœ๊ธ‰ ๋กœ์ง ๊ตฌํ˜„
        return "NEW_ACCESS_TOKEN";
    }
}

 

์„ค๋ช…

 

  • Authenticator: ์ธ์ฆ ์‹คํŒจ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ, ์ƒˆ๋กœ์šด ์ธ์ฆ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์š”์ฒญ์„ ์žฌ์‹œ๋„ํ•œ๋‹ค.
  • authenticate(): ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๊ตฌ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์š”์ฒญ์ด ์ž๋™์œผ๋กœ ๋‹ค์‹œ ์‹œ๋„๋œ๋‹ค.

๊ฒฐ๋ก  

Retrofit2์—์„œ ๊ณตํ†ต ํ—ค๋” ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ ๋ฐฉ๋ฒ•์€ ํŠน์ • ์ƒํ™ฉ์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

  • Interceptor๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด ๊ณตํ†ต์ ์ธ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • @Header ์–ด๋…ธํ…Œ์ด์…˜์€ ๋™์ ์œผ๋กœ ํ—ค๋”๋ฅผ ์„ค์ •ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.
  • @Headers ์–ด๋…ธํ…Œ์ด์…˜์€ ๊ณ ์ •๋œ ํ—ค๋” ๊ฐ’์„ ํŠน์ • ์š”์ฒญ์— ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.
  • Authenticator๋Š” ์ž๋™์œผ๋กœ ํ† ํฐ์„ ๊ฐฑ์‹ ํ•˜์—ฌ ์ธ์ฆ ์š”์ฒญ์„ ์žฌ์‹œ๋„ํ•  ๋•Œ ์ ํ•ฉํ•˜๋‹ค.

ํ”„๋กœ์ ํŠธ์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ด Retrofit2์—์„œ ํ—ค๋”๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.