728x90
헤더 요청 방식
헤더 요청 방식 형태의 예
interface SearchService {
@Headers("Authorization: KakaoAK ${REST_API_KEY}")
@GET("image")
suspend fun searchImage(@Query("query") query: String): ImageListResponse
@Headers("Authorization: KakaoAK ${REST_API_KEY}")
@GET("vclip")
suspend fun searchVideo(@Query("query") query: String): VideoListResponse
}
이런 형태의 요청을 OkHttpClient를 생성할 때 addInterceptor에 추가해주면 된다.
class HeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain
.request()
.newBuilder()
.addHeader("Authorization", "KakaoAK ${REST_API_KEY}")
.build()
return chain.proceed(request)
}
}
RetrofitManager 오브젝트
object RetrofitManager {
private val okhttpClient by lazy {
OkHttpClient
.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.addInterceptor(HeaderInterceptor()) //header 삽입//
.build()
}
private val gson by lazy {
GsonBuilder()
.setLenient()
.setDateFormat("yyyy-MM-dd'T':HH:mm:ss.SSSXXX")
.create()
}
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okhttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
val searchService: SearchService by lazy { retrofit.create(SearchService::class.java) }
class HeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain
.request()
.newBuilder()
.addHeader("Authorization", "KakaoAK ${REST_API_KEY}")
.build()
return chain.proceed(request)
}
}
}
쿼리 요청 방식
쿼리 요청 방식 형태의 예
interface FetchRemoteDatasource {
@GET("pblprfr")
suspend fun fetchShowList(
@Query("service") service:String = KOPIS_API_KEY
@Query("stdate") stdate: String,
@Query("eddate") eddate: String,
@Query("cpage") cpage: String = Constants.CURRENT_PAGE,
@Query("rows") rows: String = Constants.PAGE_INDEX,
@Query("openrun") openrun: String? = null,
@Query("newsql") newsql: String? = "Y",
@Query("shcate") shcate: String? = null,
@Query("kidstate") kidstate: String? = null,
@Query("prfstate") prfstate: String? = null,
): DbsResponse
@GET("boxoffice")
suspend fun fetchTopRank(
@Query("service") service:String = KOPIS_API_KEY
@Query("ststype") ststype: String,
@Query("date") date: String = Converter.nowDateOneDayAgo()
@Query("catecode") catecode: String? = null,
@Query("area") area: String? = null,
@Query("newsql") newsql: String? = "Y",
): BoxOfsResponse
}
쿼리 요청방식은 헤더를 추가하는 방식과 약간 다름
addQureyParameter로 쿼리 파라미터를 추가해줌
//Class 형태
class ApiKeyInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val originalHttpUrl = originalRequest.url
val url =
originalHttpUrl.newBuilder().addQueryParameter("service", KOPIS_API_KEY).build()
val request = originalRequest.newBuilder().url(url).build()
return chain.proceed(request)
}
}
//변수 형태
private val apiKeyInterceptor = Interceptor { chain ->
val originalRequest = chain.request()
val originalHttpUrl = originalRequest.url
val url = originalHttpUrl.newBuilder().addQueryParameter("service", KOPIS_API_KEY).build()
val request = originalRequest.newBuilder().url(url).build()
chain.proceed(request)
}
마찬가지로, OkHttpClient를 생성할 때 addInterceptor로 추가
object RetrofitClient {
// API Key 삽입을 위한 인터셉터
//class 형태
class ApiKeyInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val originalHttpUrl = originalRequest.url
val url =
originalHttpUrl.newBuilder().addQueryParameter("service", KOPIS_API_KEY).build()
val request = originalRequest.newBuilder().url(url).build()
return chain.proceed(request)
}
}
//변수 형태
private val apiKeyInterceptor = Interceptor { chain ->
val originalRequest = chain.request()
val originalHttpUrl = originalRequest.url
val url = originalHttpUrl.newBuilder().addQueryParameter("service", KOPIS_API_KEY).build()
val request = originalRequest.newBuilder().url(url).build()
chain.proceed(request)
}
// OkHttpClient 설정
private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(apiKeyInterceptor) // 또는 ApiKeyInterceptor()
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.connectTimeout(15, TimeUnit.SECONDS)
.build()
// Retrofit 설정
private val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build()
}
val fetch: FetchRemoteDatasource by lazy { retrofit.create(FetchRemoteDatasource::class.java) }
val search: SearchRemoteDatasource by lazy { retrofit.create(SearchRemoteDatasource::class.java) }
}
두 코드 모두 동일한 기능을 수행하지만, 클래스 형태가 가독성과 재사용성 측면에서 조금 더 나을 수 있음
- 가독성 : 클래스 형태는 코드의 구조가 명확하고 가독성이 높다.
- 재사용성 : 클래스 형태는 다른 곳에서 재사용하기 용이하다.
- 간결성: 변수 형태는 람다 표현식을 사용하여 간결하게 Interceptor를 구현할 수 있다.