Android - Retrofit2을 사용하여 RestAPI 연동 (Kotlin) (1)

업데이트:

Retrofit2을 활용한 RestAPI 연동

개요

Retrofit

image

Retrofit은 안드로이드와 자바, 코틀린에서 쉽게 RESTful API와 통신을 할 수 있도록 도와주는 라이브러리입니다.

기존의 httpConnection을 통한 방법보다 호출이나 비동기 처리 등 이용이 손쉽고, 속도도 Volley 등 다른 라이브러리보다 빨라서 대세 라이브러리로 자리잡고 있습니다.

그럼 이제 Retrofit을 활용하여 RestAPI를 연동하는 방법을 알아보도록 합시다.


네이버 API 설정

우선 네이버 개발자 등록 후, 사용할 API를 설정해야 합니다.

다음 네이버 개발자 페이지로 가서 로그인 후, 앱을 등록합니다.

https://developers.naver.com/main/


앱을 등록하고 필요한 API를 설정합니다.
예제에서는 검색과 파파고 번역 API를 사용합니다.

image


이후 클라이언트 ID와 비밀번호를 기억해둡니다.
이제 모든 준비는 끝났습니다.

image


초기 설정

우선 앱 수준 그래들에 다음과 같이 Retrofit에 관련된 라이브러리를 추가해줍니다.

implementation 'com.squareup.retrofit2:converter-gson:2.6.2' 
implementation 'com.squareup.retrofit2:retrofit:2.6.0'


그리고 매니페스트에 인터넷 접속 권한을 허용합니다.

<uses-permission android:name="android.permission.INTERNET"/>


RestAPI 통신

뉴스 검색 RestAPI 연동 - GET

네이버 검색 API를 먼저 연동해보겠습니다.
다음과 같이 파싱할 값을 저장할 데이터 클래스를 먼저 생성해줍니다.


데이터 클래스 생성

// ResultGetSearchNews.kt

data class ResultGetSearchNews(
    var lastBuildDate: String = "",
    var total: Int = 0,
    var start: Int = 0,
    var display: Int = 0,
    var items: List<Items>
)

data class Items(
    var title: String = "",
    var originallink: String = "",
    var link: String = "",
    var description: String = "",
    var pubDate: String = ""
)


API 인터페이스 생성

API 인터페이스를 생성합니다.
GET 방식으로 값을 받아오겠다는 것을 애너테이션으로 명시해줍니다.

Header 부분은 네이버 개발자 아이디와 비밀번호를 넣어야하는데 이 부분도 다음과 같이 간단히 처리할 수 있습니다.

Query 부분은 실제로 함수를 호출할 때 필요한 파라미터로 값을 전달합니다. null로 처리를 하면, 입력을 생략할 수 있습니다.

// NaverAPI.kt

interface NaverAPI {
    @GET("v1/search/news.json")
    fun getSearchNews(
        @Header("X-Naver-Client-Id") clientId: String,
        @Header("X-Naver-Client-Secret") clientSecret: String,
        @Query("query") query: String,
        @Query("display") display: Int? = null,
        @Query("start") start: Int? = null
    ): Call<ResultGetSearchNews>
}


Retrofit 초기화 및 호출

이제 실제로 API 호출을 해보면 다음과 같이 작성하면 됩니다.
Retrofit을 초기화한 후, 사용할 API 함수를 파라미터를 넘겨서 호출합니다.

그리고 enqueue로 동작하게 되는데, 이는 실제로 메인 UI 쓰레드에서 동작할 수 없기 때문에 비동기로 동작합니다.

메인 UI 쓰레드로 동작하려면 execute를 호출하여 사용합니다.

// MainActivity.kt

val CLIENT_ID = "네이버_개발자센터_아이디"
val CLIENT_SECRET = "네이버_개발자센터_비밀번호"
val BASE_URL_NAVER_API = "https://openapi.naver.com/"

val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL_NAVER_API)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
val api = retrofit.create(API::class.java)
val callGetSearchNews = api.getSearchNews(CLIENT_ID, CLIENT_SECRET, "테스트")

callGetSearchNews.enqueue(object : Callback<ResultGetSearchNews> {
    override fun onResponse(
        call: Call<ResultGetSearchNews>,
        response: Response<ResultGetSearchNews>
    ) {
        Log.d("결과", "성공 : ${response.raw()}")
    }

    override fun onFailure(call: Call<ResultGetSearchNews>, t: Throwable) {
        Log.d("결과:", "실패 : $t")
    }
})


파파고 번역 RestAPI 연동 - POST

이제는 같은 방법으로 POST 방식으로 연동해보겠습니다.

데이터 클래스 생성

// ResultTransferPapago.kt

data class ResultTransferPapago (
    var message: Message
)

data class Message(
    var result: Result
)

data class Result (
    var srcLangType: String = "",
    var tarLangType: String = "",
    var translatedText: String = ""
)


API 인터페이스 생성

POST 방식은 @FormUrlEncoded 어노테이션을 사용하고 @Field로 요청 변수를 입력합니다.

// NaverAPI.kt

@FormUrlEncoded
@POST("v1/papago/n2mt")
fun transferPapago(
    @Header("X-Naver-Client-Id") clientId: String,
    @Header("X-Naver-Client-Secret") clientSecret: String,
    @Field("source") source: String,
    @Field("target") target: String,
    @Field("text") text: String
): Call<ResultTransferPapago>


Retrofit 초기화 및 호출

// MainActivity.kt

val CLIENT_ID = "네이버_개발자센터_아이디"
val CLIENT_SECRET = "네이버_개발자센터_비밀번호"
val BASE_URL_NAVER_API = "https://openapi.naver.com/"

val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL_NAVER_API)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
val api = retrofit.create(API::class.java)
val callPostTransferPapago = api.transferPapago(CLIENT_ID, CLIENT_SECRET, 
        "ko", "en", "테스트입니다. 이거 번역해주세요.")

callPostTransferPapago.enqueue(object : Callback<ResultTransferPapago> {
    override fun onResponse(
        call: Call<ResultTransferPapago>,
        response: Response<ResultTransferPapago>
    ) {
        Log.d(TAG, "성공 : ${response.raw()}")
    }

    override fun onFailure(call: Call<ResultTransferPapago>, t: Throwable) {
        Log.d(TAG, "실패 : $t")
    }
})


결론

기존의 URLConnection을 활용하는 방법보다 초기 진입 장벽은 살짝 높을 수 있지만, 훨씬 간결하고 사용하기 편하며 신경써야할 부분이 적어졌음을 알 수 있습니다.


댓글남기기