전에 작성했던 글 안에 Retrofit과 OkHttp에 대해서 간단하게 작성했었는데 더 자세하게 정리하기 위해 분리.
Retrofit ?
- Retrofit은 Type - safe한 REST 통신 라이브러리이다. RESTful API를 호출하고 JSON 또는 XML 과 같은 응답 데이터를 쉽게 파싱할 수 있도록 도와준다.
- 이때 REST란 Representational State Transfer의 약자로 웹 서비스를 구축하기 위한 아키텍처 스타일이며, REST는 네트워크 상에서 클라이언트와 서버 간의 통신을 위한 규칙(HTTP 메서드)과 제약 조건(상태 관리 등)을 정의한다.
- Json - Java Script Object Notiationn은 key - value의 쌍으로 이루어져 있는 객체를 만들 때 생성하는 표현식으로, 직관적이어서 이해하고, 작성하는 것이 쉬우며 XML에 비해 용량이 적어 일반적으로 많이 사용되는 데이터를 저장하거나 전송할 때 쓰이는 문자 형식이다.
- OkHttp 라이브러리의 상위 구현체로, OkHttp를 네트워크 계층으로 활용하고 그 위에 구축된다. API 30부터 deprecated된 Async Task를 통해 작업하는 방식이 아닌 AsyncTask 없이 Background Thread를 실행하고 Callback을 통해 Main Thread에서 UI를 업데이트할 수 있다.
OkHttp ?
- OkHttp에 대해서도 간단하게 알아보자
- OkHttp는 Http 클라이언트 라이브러리 이다. OkHttp는 애플리케이션에서 네트워크 통신을 처리하는 데 사용된다.
- OkHttp의 장점
- HTTP/1,2,3 프로토콜을 지원하여 빠르고 효율적인 네트워크 통신을 가능하게 한다.
- HTTP/2,3 프로토콜 ?
- 웹 통신을 위해 최신 버전의 프로토콜이다. 빠르고 효율적인 네트워크 통신을 가능하게 한다
- 인터셉터 지원
- OkHttp는 인터셉터를 사용하여 요청 및 응답을 수정하고 로깅할 수 있다. 이를 통해 네트워크 요청과 Response를 받아 필요한 작업을 수행할 수 있다.
- Caching
- Caching? 이전에 수신한 네트워크 응답을 로컬 또는 메모리에 저장하는 것.
- 반복적인 요청에 대한 네트워크 비용과 시간이 절약.
- 불안정한 네트워크 연결 상황에서도 이전에 수신되어 캐시된 응답을 사용하므로 안정성 향상.
- 네트워크 대역폭을 절약하며 서버 부하를 줄여줌으로 시스템의 전반적인 성능 향상.
- OkHttp는 HTTP응답을 캐싱하여 네트워크 사용량을 줄이고 응답 시간을 단축할 수 있도록 한다.
- Caching? 이전에 수신한 네트워크 응답을 로컬 또는 메모리에 저장하는 것.
- HTTP/1,2,3 프로토콜을 지원하여 빠르고 효율적인 네트워크 통신을 가능하게 한다.
- OkHttp가 Retrofit의 Base로 사용되는 이유.
- OkHttp를 사용하지 않고 HTTP 통신을 하기 위해서는 다음과 같은 과정을 통해야한다
- 1. HttpURLConnection 연결
- 2. Buffer를 통한 입출력
- 3. 예외 처리 등
- 하지만 OkHttp를 사용하게 될 경우 이러한 부분을 해결할 수 있다. 이로 인해 Retrofit 라이브러리에서 내부 코드에서도 OkHttp 클라이언트를 디폴트로 선언한다.
- OkHttp를 사용하지 않고 HTTP 통신을 하기 위해서는 다음과 같은 과정을 통해야한다
API Service 인터페이스 ( Retrofit Service Interface )
- API Service Interface 의 역할은 Retrofit을 사용하여 원격 API와 통신하기 위해 End Point와 메서드를 정의하여 해당 네트워크 요청 및 API 호출에 대한 응답을 처리할 수 있도록 한다.
- API Service Interface의 구성요소
- API End Point에 대한 요청
- HTTP 요청 방식 ( GET, POST, PUT, DELETE 등 ) 을 통해 API 요청 경로와, 쿼리 매개변수, 요청 바디 등을 동적으로 요청 방식을 바인딩할 수 있다.
- 쿼리 매개변수
- @Query, @QueryMap 과 같은 형태로 API 요청 메서드의 프로퍼티 값들을 지정해준다.
- 응답 처리
- API 요청 메서드를 통해 반환된 응답의 수신받는 형식( Response, Call, Deferred 등 ) 과 타입을 지정해주는 것이다.
- API End Point에 대한 요청
Retrofit 사용하기
build.gradle
- retrofit2 와 okhttp3, OkHttp Intercepter를 사용할 경우 okhttp3 logging-interceptor을 추가해준다.
- json 데이터의 변환이 필요하므로 gson converter 또는 moshi converter 등 의 Converter 추가
dependencies {
// retrofit, okHttp3, gson converter Library
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
// gson converter | 컨버터는 사용할 1개만 있으면 된다
implementation("com.google.code.gson:gson:2.10.1")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// moshi converter
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
...
...
}
Retrofit Instance 생성 및 apiService Interface 정의
ApiServiceInterface.kt
- 이때 API에서 별도로 Header를 특정하고 있는 경우에는 Headers를 통해 Key를 입력하고, Header가 특정되지 않은 경우에는 Get 내부 API 요청 메서드 프로퍼티로 Key 값을 지정 해줘야 한다.
- API 요청 메서드 프로퍼티 작성 후 응답처리 ( Call<> 또는 Response<>, Deferred<> ) 메소드를 정의 해준다
// header의 Key를 통해 요청하는 경우
interface ApiServiceInterface {
@Headers("Authorization: YOUR_API_KEY")
@GET("End point")
//// Response를 사용할 경우 suspend fun으로 변경.
fun service(
@Query("param0") param0: String,
@Query("param1") param1: String,
@Query("param2") param2: Int,
@Query("param3") param3: Int,
): // Call<Model> 또는 Response<Model>
// 이때 Model은 API 통신을 통해 받게될 JSON 데이터 최상단에 있는 Object.
}
// header의 key를 통해 요청하지 않는 경우
interface ApiServiceInterface {
@GET("End point")
//Response를 사용할 경우 suspend fun으로 변경.
fun service(
@Query("key") key: String,
@Query("param0") param0: String,
@Query("param1") param1: String,
@Query("param2") param2: Int,
@Query("param3") param3: Int,
): // Call<Model> 또는 Response<Model>
// 이때 Model은 API 통신을 통해 받게될 JSON 데이터 최상단에 있는 Object.
}
Object RetrofitClient.kt
- [ 1 ] object 안에서 by lazy {} 를 통해 apiService와 Retrofit이 최초 접근 시 한번만 초기화 되고, 이후에는 이미 생성된 인스턴스를 재사용하게끔 객체를 정의해주고 GsonBuilder를 정의해준다
- setLenient() =Json 파싱 시 유연한 방식으로 동작하도록 설정하는 Gson 라이브러리 메소드
- [ 2 ] Retrofit.Builder API 통신의 대상이 되는 네트워크의 BaseUrl과 ConverterFactory를 지정해준다.
OkHttp3 Intercepter를 사용하지 않는 경우
// OkHttp3 Intercepter를 사용하지 않는 경우
object RetrofitClient {
//GsonBuilder를 정의
private val retrofit: Retrofit by lazy {
val gson = GsonBuilder().setLenient().create()
//Retrofit.Builder 정의
Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
// retrofit의 api 서비스 Interface 정의
val apiService: RetrofitInterface by lazy {
retrofit.create(RetrofitInterface::class.java)
}
}
OkHttp3 Intercepter를 사용하는 경우, API Service Interface 응답 처리 메소드를 Response<T> 로 사용한다.
// OkHttp3 Intercepter를 사용하는 경우
object RetrofitClient {
// OkHttpClient 객체 정의
private val okHttpClient: OkHttpClient by lazy {
val interceptor = HttpLoggingInterceptor()
if (BuildConfig.DEBUG)
interceptor.level = HttpLoggingInterceptor.Level.BODY
else
interceptor.level = HttpLoggingInterceptor.Level.NONE
OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.addNetworkInterceptor(interceptor)
.build()
}
private val retrofit: Retrofit by lazy {
//GsonBuilder를 정의
val gson = GsonBuilder().setLenient().create()
//Retrofit.Builder 정의
Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient) // okHttpClient객체 client 지정
.build()
}
// retrofit의 api 서비스 Interface 정의
val apiService: RetrofitInterface by lazy {
retrofit.create(RetrofitInterface::class.java)
}
}
응답 처리 메소드 ( API Response Handling Method )
- 응답 처리 메소드는 Retrofit에서 제공하는 Response<T>, Call<T> 과 Coroutine 라이브러리에서 제공해주는 Deferred<T> 가 일반적으로 사용된다.
- Retrofit2 에서 제공해주는 Call과 Response에 대해서 알아보자.
Call < T >
- 자체적으로 HTTP 요청과 응답 쌍을 생성한다 → OkHttp를 사용하지 않고 사용할 때 주로 사용된다.
- 수신 받을 Data 객체를 T 에 넣어주어 Call<수신받을객체> 형식으로 메소드 사용.
- execute()를 사용해 동기적으로 실행 또는 enqueue()를 사용해 비동기적으로 실행이 가능하다.
- execute()
- execute()는 동기적으로 요청을 보내고 응답을 반환한다. Retrofit의 동기 호출은 메인 쓰레드에서 실행되기 때문에 execute()가 실행되는 동안 UI가 차단되어 유저와 UI 간의 상호작용이 불가능하기 때문에 권장되지 않는 방법이다
- enqueue()
- enqueue() 는 비동기적으로 요청을 보내고 응답을 반환하므로 execute()처럼 메인 쓰레드에서 실행되지 않기 때문에 유저와 UI 간의 상호작용은 메인 쓰레드에서 정상적으로 작동될 수 있다.
- 비동기적인 응답처리를 위해 응답 성공 또는 실패 시 동작을 정의할 콜백객체 ( Callback<T> ) 를 구현해주어야 한다.
- execute()
class testA : Fragment() {
// 콜백 구현
call.enqueue(object : Callback<User> {
override fun onResponse(call: Call<User>, response: Response<User>) {
if (response.isSuccessful) {
val user: User? = response.body()
// 성공적인 응답 처리
}else {
// 오류 응답 처리
}
}
override fun onFailure(call: Call<User>, t: Throwable) {
// 네트워크 오류 처리
}
}
}
Response<T>
- 응답 처리 메서드로 Response<T> 을 사용하게 될 경우 보통 OkHttp3와 함께 사용한다.
- 응답 데이터로는 response.body() 메서드를 통해 수신된 응답 데이터를 가져올 수 있다.
- suspend 를 통해 코루틴 사용으로 비동기적인 처리가 가능하다.
- 에러 처리 try , catch 사용 - enqueue 에 비해 간결한 코드 작성 가능.
class testFragment : Fragment() {
private lateinit var apiServiceinterface : ApiServiceInterface
...
...
// 파라미터를 받지않고 apiServiceInterface.service() 괄호 안에서 하드코딩 하는 방법도 있다
fun api(key: String, param0 : String param2: Int) = globalScope.launch(Dispatchers.IO){
try {
val response:Response<T> = apiServiceInterface.service(key,param0,"test",param2,5)
if (response.isSuccessful){
response.body()?.let{ body ->
//성공 처리
}
}else {
val errorBody: ResponseBody? = response.errorBody()
// 실패 처리
}
}catch (e: Exception){
// 예외 처리
}
}
}
[오늘 복습한 내용]
1. Retrofit, OkHttp
[오류,에러 등등]
1. 특별한 오류는 없었다.
[느낀 점]
1. 작동 개념을 이해하기가 어려울 때 천천히 코드를 하나씩 뜯어보면 답을 찾는 것 같다.
2. 어렵다
3. 남한테 쉽게 이해할 수 있게 설명하기가 너 어렵다
[Reference]
// Call vs Response
https://velog.io/@jeongminji4490/Retrofit-Call-vs-Response-and-Kotlin-Result
'TIL' 카테고리의 다른 글
[TIL] kotlin Room Database 개념 (0) | 2023.10.01 |
---|---|
[TIL] kotlin Youtube Data API 3 - [ 2 ] videos:List 받아와 Trending 10 Thumbnails 만들기 (2) | 2023.09.30 |
[TIL] kotlin Youtube Data API 3 - [ 1 ] 기본 설정 (0) | 2023.09.26 |
[TIL] Kotlin SQLite (0) | 2023.09.23 |
[TIL] Kotlin Coroutine의 구조와 간단한 예제 (0) | 2023.09.22 |