App/개발

[안드로이드] retrofit2, okhttp3를 이용한 http 요청 api 만들기(+ interceptor로 인증 헤더 넣기)

Say simple 2020. 9. 7. 22:46
728x90
반응형

1. retrofit2와 okhttp3, gson 빌더를 싱글톤으로 생성한다

빌더를 만드는 것은 한 번 만들고 다시 코드를 적을일 없으니 저장해놓고 쓰도록 하자.

import com.connple.weat.api.model.Notification
import com.connple.weat.api.model.User
import okhttp3.MultipartBody
import retrofit2.Call
import retrofit2.http.*

object MyApp {
    private lateinit var retrofit: Retrofit
    private val signedIn get() = authToken != null
    
    fun update(
    	baseUrl: String? = null,
        authToken: String? = null
    ) {
    MyApp.authToken = authToken ?: MyApp.authToken
    val retrofitBuilder = Retrofit.Builder()

    val clientBuilder = OkHttpClient.Builder()
    if (signedIn) clientBuilder.addInterceptor(AuthorizationHeaderInterceptor(MyApp.authToken!!))
	val GsonBuilder = GsonBuilder().setLenient()
    
    retrofitBuilder.baseUrl(MyApp.baseUrl)
            .client(clientBuilder.build())
            .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    retrofit = retrofitBuilder.build()
    
    me = retrofit.create(MeService::class.java)
    
  
    }
    
    init{
    	update()
    }
    
    AuthorizationHeaderInterceptor(private val authToken: String) : Interceptor{
    	override fun intercept(chain: Interceptor.Chain): Response{
        	val resquestBuilder = chain.request().newBuilder()
            
            requestBuilder.removeHeader("authorization").addHeader("authorization", authToken)
            
            return chain.proceed(requestBuilder.build())
        }
    }
    

 

2. retrofit2의 서비스 인터페이스를 만든다.

interface MeService{
	
    
    @GET("user")
    fun get(): Call<User>
    
    @GET("user/{:id}/following")
    fun getFollowing(@Path("id") id: Int) : Call<List<Following>>
    
    @GET("users")
    fun getUsers(@Query("cursor") cursor: Int) : Call<List<User>>
    
    @FormUrlEncoded
    @POST("user")
    fun update(@Field("id") id: Int,
    		@Field("username") username: String
    ) : Call<User>
}

 

 

@GET, @POST, @PUT, @DELETE 이렇게 네가지 메소드를 사용할 수 있는데 사용법은 위와 같다.

주로 사용하는 태그는 @Path, @Query, @Field, @Body 가 있다.

url에 인자를 넣는 법은 {:id}와 같이 넣으면 되고 @Path 어노테이션을 붙여서 요청한다.

쿼리는 @Query 어노테이션을 붙여서 사용하면 된다.

@Field의 @FormUrlEncoded는 인자를 key=value&key=value 형식으로 보내는 것이고 @Field("key") value: Any와 같은 형식으로 사용하면 된다.

@FormUrlEncoded는 @Field를 이용하기 위해서 꼭 필요한 어노테이션이다.

@Body 태그도 존재하는데 이는 key=value 형식이 아닌 http 헤더의 body에 담아서 보내는 것이다.

 

3. 만든 인터페이스를 이용해서 웹 요청을 보낸다.

인터페이스를 사용하는 방식은 두 가지가 있다. 안드로이드는 기본적으로 메인 스레드에서 네트워크 요청을 보내지 못하기 때문에 따로 스레드를 생성해서 네트워크 요청을 하는데 레트로핏에서는 기본적으로 네트워크 요청을 보내는 함수를 지원한다.

레트로핏에서 지원하는 함수

MyApp.me.get().enqueue(object : Callback<User> {
	override fun onResponse(call: Call<User>, response: Response<User>) {
		val value = response.body()
	}

	override fun onFailure(call: Call<User>, t: Throwable) {
		println("네트워크 요청 실패")
	}
})

 

지원하는 함수를 사용하지 않고 만들기 위해서는 따로 스레드를 만들거나 코루틴을 이용해야 한다.

나는 주로 코루틴을 이용하므로 코루틴을 이용한 코드로 예시를 넣었다.

 

        GlobalScope.launch(Dispatchers.IO) {
            val response = MyApp.me.get().execute()
            if(response.isSuccessful) {
                val value = response.body()
            }else{
                // 실패시 할 작업
            }
        }

GlobalScope란 코루틴이 분리되어 존재할 범위를 나타내는 것이고 .launch는 코루틴을 실행하는 것이다.

(Dispatchers.IO)에서  Dispatcher는 코루틴에서 사용할 스레드를 고른다. 스레드에는 IO, Main, Default가 있다.

안드로이드는 정책 상 메인 스레드에서 네트워크 요청을 보내지 못하므로 IO스레드로 교체해주고 요청을 보낸다.

 

결과적으로 정리하면 retrofit2로 네트워크 요청을 보내고 okhttp3로 인증 헤더를 넣어서 사용하는 방식이다.

+ User 모델은 아래와 같이 data class로 작성하였다.

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import java.util.*

@Parcelize
data class User(
    var id: String,
    var createdAt: Date,
    var updatedAt: Date,
	var username: String
) : Parcelable
728x90
반응형