Kotlin에서 Retrofit을 이용한 API 연동

안녕하세요, 여러분! 오늘은 앱 개발하면서 정말 많이 쓰이는 API 연동에 대해 같이 알아보려고 해요. API 연동, 생각만 해도 머리 아프고 괜히 어렵게 느껴지지 않나요? 하지만 걱정 마세요! Kotlin의 강력한 친구, Retrofit을 사용하면 훨씬 쉽고 간편하게 API 연동을 할 수 있답니다. 마치 마법처럼요! ✨

Retrofit은 마치 훌륭한 통역사처럼 우리의 앱과 서버 사이에서 데이터를 주고받는 걸 도와주는 라이브러리예요. 복잡한 코드 없이도 깔끔하고 효율적으로 API를 사용할 수 있도록 해준답니다. 이 블로그 글에서는 Retrofit의 기본 설정부터 API 인터페이스 정의, 요청 및 응답 처리, 그리고 실제 API 연동 예제까지 차근차근 살펴볼 거예요. 자, 그럼 Kotlin과 Retrofit을 이용해서 API 연동의 세계로 함께 떠나볼까요? 두려워하지 마세요. 생각보다 훨씬 재밌을 거예요!

 

 

Retrofit 기본 설정

자, 이제 드디어 본격적으로 Retrofit을 설정해 볼 시간이에요! 마치 레고 블록을 하나씩 끼워 맞추듯, 차근차근 따라오시면 어렵지 않게 설정을 마칠 수 있을 거예요. 😉 Retrofit을 사용하려면 먼저 몇 가지 필수적인 설정 과정을 거쳐야 하는데, 마치 맛있는 요리를 만들기 위한 기본 재료 준비와 같다고 생각하시면 돼요. 잘 따라와 주세요!

라이브러리 추가

먼저, 프로젝트에 Retrofit 라이브러리를 추가해야겠죠? Gradle을 사용하신다면 build.gradle 파일의 dependencies 블록 안에 다음과 같이 추가해 주세요. 버전은 최신 버전을 사용하는 것을 추천드려요! (최신 버전 정보는 Retrofit 공식 문서에서 확인 가능해요!)

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0' // Retrofit 라이브러리
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Gson Converter
}

Gson Converter는 JSON 형식의 데이터를 Java 객체로 변환해 주는 역할을 해요. API 통신에서 가장 많이 사용되는 데이터 형식이 JSON이기 때문에 거의 필수적으로 추가한다고 보시면 돼요. XML을 사용하신다면 converter-simplexml을 사용하시면 됩니다! 다른 Converter들도 있으니 필요에 따라 추가해 주세요.

Retrofit 객체 생성

라이브러리를 추가했다면 이제 Retrofit 객체를 생성해야 해요. Retrofit 객체는 API 통신을 위한 핵심 객체라고 할 수 있어요. 마치 모든 API 요청의 관문과 같은 역할을 한다고 생각하시면 됩니다. Retrofit 객체를 생성할 때는 baseUrl을 설정해 주어야 하는데, 이는 API 서버의 기본 주소를 의미해요. 예를 들어, https://api.example.com과 같이 설정할 수 있겠죠?

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com") // baseUrl 설정! 잊지 마세요!
    .addConverterFactory(GsonConverterFactory.create()) // Gson Converter 추가!
    .build()

baseUrl 뒤에 붙는 경로는 API 인터페이스에서 정의하게 돼요. 이렇게 baseUrl을 따로 설정하는 이유는 코드의 중복을 줄이고 관리를 편하게 하기 위해서예요. 만약 baseUrl이 변경되면 이 부분만 수정하면 되니까 훨씬 효율적이겠죠? 👍

자, 여기서 중요한 포인트! addConverterFactory() 메서드를 통해 Gson Converter를 추가했는데요, 이 부분이 JSON 데이터를 Java 객체로 변환해 주는 역할을 한다는 것을 잊지 마세요! 만약 다른 Converter를 사용한다면 이 부분을 수정해 주어야 합니다.

API 인터페이스 정의

이렇게 Retrofit 객체를 생성하고 나면 API 인터페이스를 정의해야 해요. API 인터페이스는 API 요청을 정의하는 부분이에요. 각각의 API 요청은 인터페이스의 메서드로 정의되며, 메서드에 어노테이션을 사용하여 HTTP 메서드(GET, POST, PUT, DELETE 등), 요청 경로, 파라미터 등을 지정할 수 있어요. 마치 API 요청 설계도를 그리는 것과 같다고 생각하시면 돼요. 📐

예를 들어, /users 경로로 GET 요청을 보내는 API를 정의하려면 다음과 같이 작성할 수 있어요.

interface UserService {
    @GET("/users")
    fun getUsers(): Call<List<User>>
}

@GET 어노테이션은 HTTP GET 메서드를 사용한다는 것을 의미하고, /users는 요청 경로를 나타내요. Call<List<User>>는 응답 데이터를 User 객체의 리스트로 받겠다는 것을 의미해요. 이 부분은 다음에 자세히 설명드릴게요! 😊

API 인터페이스 구현체 생성

이제 Retrofit 객체를 사용하여 API 인터페이스의 구현체를 생성할 수 있어요.

val userService = retrofit.create(UserService::class.java)

이렇게 생성된 userService 객체를 사용하여 API 요청을 보낼 수 있게 됩니다! 🎉

여기까지 Retrofit 기본 설정에 대해 알아봤어요. 어때요, 생각보다 간단하지 않나요? 물론 처음에는 조금 낯설 수도 있지만, 몇 번 연습하다 보면 금방 익숙해질 거예요. 다음에는 API 인터페이스를 정의하는 방법에 대해 자세히 알아보도록 할게요! 기대해 주세요! 😉

 

API 인터페이스 정의

자, 이제 드디어 Retrofit을 사용해서 API 호출을 하기 위한 인터페이스를 정의하는 단계에 왔어요! 마치 건축물의 설계도를 그리는 것처럼, 어떤 데이터를 주고받을지 미리 약속하는 과정이라고 생각하면 돼요. 잘 설계된 인터페이스는 코드의 가독성과 유지보수성을 높여주는 중요한 역할을 한답니다!

Retrofit은 인터페이스를 통해 네트워크 요청을 추상화해요. 즉, 복잡한 네트워크 코드를 직접 작성할 필요 없이, 마치 메서드를 호출하듯이 간편하게 API를 사용할 수 있도록 도와준다는 거죠!

API 인터페이스 정의의 중요 요소

API 인터페이스를 정의할 때는 몇 가지 중요한 요소들이 있어요. 함께 하나씩 살펴보도록 할까요?

HTTP 메서드 지정

먼저, HTTP 메서드를 지정해야 해요. GET, POST, PUT, DELETE 등 API의 기능에 맞는 메서드를 @GET, @POST, @PUT, @DELETE 어노테이션을 사용하여 인터페이스 메서드 위에 명시해 줘야 하죠. 예를 들어, 게시글 목록을 가져오는 API라면 @GET("/posts")처럼 사용할 수 있어요. 만약 특정 게시글을 가져오는 API라면 @GET("/posts/{id}")와 같이 경로 파라미터를 사용할 수 있고요. {id} 부분에 실제 게시글 ID가 들어가게 되는 거죠!

요청 파라미터 정의

다음으로, 요청 파라미터를 정의해야 해요. API에 데이터를 전달해야 하는 경우, @Query, @Path, @Body 등의 어노테이션을 사용해서 파라미터를 정의할 수 있어요. @Query는 쿼리 파라미터를, @Path는 경로 파라미터를, @Body는 요청 본문을 나타내죠. 예를 들어, @Query("page") int pagepage라는 이름의 쿼리 파라미터를 정수형으로 전달하는 것을 의미해요. @Path("id") int postId는 경로 파라미터 idpostId 변수에 매핑하는 것을 의미하고요. 만약 JSON 형태의 데이터를 전달해야 한다면 @Body RequestBody body처럼 사용할 수 있답니다.

응답 데이터 객체 정의

마지막으로, 응답 데이터를 받을 객체를 정의해야 해요. API 호출 결과로 받을 데이터를 Java 또는 Kotlin 클래스로 정의하고, 인터페이스 메서드의 반환 타입으로 지정하면 돼요. Retrofit은 Gson이나 Moshi와 같은 JSON 변환 라이브러리를 사용하여 응답 데이터를 자동으로 객체로 변환해 줘요. 예를 들어, Call> getPosts()는 게시글 목록을 Post 객체의 리스트 형태로 받아오는 것을 의미한답니다.

코드 예시

자, 이제 실제 코드 예시를 통해 좀 더 자세히 알아볼까요? 예를 들어, GitHub API에서 사용자 정보를 가져오는 인터페이스를 정의한다고 가정해 봅시다.

interface GitHubService {
    @GET("/users/{user}")
    fun getUser(@Path("user") user: String): Call<User>

    @GET("/users/{user}/repos")
    @Headers("Accept: application/vnd.github.v3+json")  // 특정 헤더 추가!
    fun listRepos(@Path("user") user: String, @Query("page") page: Int): Call<List<Repo>>
}

위 코드에서 getUser() 메서드는 user라는 경로 파라미터를 받아서 특정 사용자의 정보를 가져오는 API를 나타내고, listRepos() 메서드는 user라는 경로 파라미터와 page라는 쿼리 파라미터를 받아서 특정 사용자의 저장소 목록을 페이지별로 가져오는 API를 나타내요. @Headers 어노테이션을 사용하여 특정 헤더를 추가할 수도 있고요. UserRepo는 각각 사용자 정보와 저장소 정보를 담는 데이터 클래스랍니다.

이처럼 Retrofit을 사용하면 API 인터페이스를 간결하고 명확하게 정의할 수 있어요. 복잡한 네트워크 코드 대신 비즈니스 로직에 집중할 수 있게 되는 거죠! 다음 단계에서는 이렇게 정의한 인터페이스를 사용해서 실제로 API를 호출하고 응답을 처리하는 방법에 대해 알아보도록 할게요.

 

요청 및 응답 처리

후~ 드디어 Retrofit의 꽃이라고 할 수 있는 부분에 도착했어요! API 인터페이스를 정의했으니 이제 실제로 데이터를 주고받는 방법을 알아봐야겠죠? 마치 편지를 보내고 답장을 받는 것처럼 말이에요! 자, 그럼 두근두근 시작해 볼까요?

Retrofit은 OkHttp를 기반으로 네트워크 통신을 처리해요. OkHttp는 안드로이드에서 HTTP 요청을 보내고 응답을 받는 데 널리 사용되는 강력한 라이브러리랍니다. Retrofit은 이 OkHttp를 더욱 사용하기 쉽게 감싸준 멋진 친구라고 생각하면 돼요!

요청 보내기

자, 이제 본격적으로 요청을 보내는 방법을 알아볼게요. @GET, @POST, @PUT, @DELETE와 같은 어노테이션을 사용해서 HTTP 메서드를 지정할 수 있어요. 예를 들어, GET 요청을 보내려면 @GET("/users")와 같이 작성하면 된답니다. 참 쉽죠? URL 경로는 /users처럼 간단하게 작성할 수도 있고, /users/{id}와 같이 Path Variable을 사용해서 동적으로 URL을 구성할 수도 있어요! 만약 id가 123인 사용자 정보를 가져오고 싶다면 /users/123처럼 요청을 보내면 되겠죠?

@Query, @Path, @Body와 같은 어노테이션들을 사용하면 요청 파라미터를 추가할 수 있어요. 쿼리 파라미터를 추가하고 싶다면 @Query("page") int page와 같이 작성하면 되고, Path Variable을 사용할 때는 @Path("id") int id 와 같이 작성하면 된답니다. POST 요청처럼 Body에 데이터를 담아 보내야 할 때는 @Body User user와 같이 사용하면 돼요. 참 편리하죠?

응답 받기

응답을 받는 부분도 정말 중요해요! Retrofit은 Call 객체를 반환하는데, 이 객체를 사용해서 비동기적으로 응답을 처리할 수 있어요! enqueue() 메서드를 사용하면 백그라운드 스레드에서 네트워크 요청을 보내고, 응답이 오면 onResponse() 콜백 메서드가 호출된답니다. onResponse() 메서드에서는 response.body()를 통해 응답 본문에 접근할 수 있어요. 만약 요청이 실패하면 onFailure() 콜백 메서드가 호출되고, 여기서 에러를 처리할 수 있죠!

응답을 처리할 때 Gson과 같은 JSON 파서 라이브러리를 함께 사용하면 JSON 형식의 응답 데이터를 자바 객체로 쉽게 변환할 수 있어요! Retrofit에서 Gson Converter를 사용하려면 GsonConverterFactory를 추가하면 된답니다. 정말 간단하죠?! Gson 외에도 Moshi, Jackson과 같은 다른 JSON 파서 라이브러리도 사용할 수 있어요. 선택은 자유!

실제 코드 예시

자, 그럼 실제 코드를 보면서 이해를 돕도록 할게요! 예를 들어, GitHub API에서 사용자 정보를 가져오는 요청을 보낸다고 가정해 볼게요. @GET("/users/{username}") 어노테이션을 사용해서 GET 요청을 보내고, @Path("username") 어노테이션을 사용해서 username을 Path Variable로 전달할 수 있어요. 응답은 Call 객체로 받고, enqueue() 메서드를 사용해서 비동기적으로 응답을 처리하면 된답니다.

만약 HTTP 상태 코드가 200 OK이면 response.body()를 통해 User 객체에 접근할 수 있고, 404 Not Found와 같은 에러가 발생하면 onFailure() 메서드에서 에러를 처리할 수 있겠죠? response.code()를 통해 HTTP 상태 코드를 확인할 수도 있고, response.errorBody()를 통해 에러 메시지를 확인할 수도 있어요! 정말 유용하죠?

Retrofit은 다양한 HTTP 응답 코드(200 OK, 400 Bad Request, 500 Internal Server Error 등)를 처리할 수 있도록 설계되어 있어 안전하고 효율적인 네트워크 통신을 구현할 수 있게 도와준답니다! 또한, 요청 타임아웃, 재시도 횟수 등 다양한 설정 옵션을 제공해서 네트워크 환경에 맞게 유연하게 대응할 수 있어요.

이처럼 Retrofit을 사용하면 HTTP 요청을 보내고 응답을 처리하는 작업을 매우 간편하게 할 수 있어요! 복잡한 네트워크 코드를 직접 작성할 필요 없이, 어노테이션과 콜백 메서드를 사용해서 깔끔하고 효율적인 코드를 작성할 수 있답니다. 개발 시간을 단축하고 코드의 가독성을 높이는 데 큰 도움이 되겠죠?

 

실제 API 연동 예제

드디어! 기다리고 기다리던 실제 API 연동 예제 시간이에요! 앞에서 힘들게(?) Retrofit 기본 설정하고, API 인터페이스 정의하고, 요청 및 응답 처리까지 했으니 이제 실제로 써먹어 봐야죠?! 두근두근~?

자, 이번 예제에서는 공공 데이터 포털에서 제공하는 “전국 도서관 정보” API를 사용해볼 거예요. 이 API는 JSON 형태로 데이터를 제공하고, 도서관 이름, 주소, 전화번호 등 유용한 정보들을 담고 있어요. 실제 서비스에서 활용하기에도 딱! 좋겠죠? ^^ 자 그럼, 시작해 볼까요?

의존성 추가

먼저, 의존성 추가부터 해야겠죠? build.gradle 파일을 열고 다음과 같이 Retrofit과 Gson Converter를 추가해 주세요. Gson Converter는 JSON 데이터를 Kotlin 객체로 변환해주는 역할을 해요. 잊지 마세요~!

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}

버전은 항상 최신 버전을 확인하고 사용하는 센스! 아시죠?! (찡긋)

Data Class 생성

자, 이제 데이터를 받아올 Data Class를 만들어 볼게요. Kotlin의 강력한 data class 기능을 사용하면 간편하게 만들 수 있어요!

data class Library(
    val library_name: String,
    val address: String,
    val telephone: String?, // 전화번호가 없는 도서관도 있을 수 있으니 nullable로 처리!
    // ... 필요한 다른 필드들도 추가해주세요!
)

API 인터페이스 정의

다음으로, API 인터페이스를 정의해야 해요. @GET 어노테이션을 사용하여 API 엔드포인트를 지정하고, @Query 어노테이션을 사용하여 쿼리 파라미터를 추가할 수 있어요. 공공 데이터 포털 API는 보통 페이지 번호와 페이지당 결과 수를 지정하는 파라미터를 필요로 하니, 이 부분도 꼼꼼하게 챙겨야 해요!

interface LibraryApi {
    @GET("도서관_API_엔드포인트") // 실제 엔드포인트로 변경해주세요!
    suspend fun getLibraries(
        @Query("page") page: Int,
        @Query("perPage") perPage: Int
    ): Response<List<Library>>
}

Retrofit 객체 생성 및 API 인터페이스 연결

이제 Retrofit 객체를 생성하고 API 인터페이스를 연결해 줍니다. baseUrl은 API의 기본 URL을 설정하는 부분이에요. GsonConverterFactory를 추가하여 JSON 데이터를 Kotlin 객체로 변환하도록 설정했어요.

val retrofit = Retrofit.Builder()
    .baseUrl("도서관_API_기본_URL") // 실제 기본 URL로 변경해주세요!
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val libraryApi = retrofit.create(LibraryApi::class.java)

API 호출 및 데이터 처리

이제 모든 준비는 끝났어요! 실제로 API를 호출하고 데이터를 받아와 볼게요. Coroutine을 사용하여 비동기적으로 API를 호출하고, 결과를 처리해요. try-catch 블록을 사용하여 예외 처리도 잊지 않아야겠죠?!

viewModelScope.launch { // Coroutine Scope 안에서 실행해야 해요!
    try {
        val response = libraryApi.getLibraries(page = 1, perPage = 10)
        if (response.isSuccessful) {
            val libraries = response.body()
            // 받아온 데이터를 UI에 표시하거나 다른 작업을 수행해요!
            libraries?.forEach { library ->
                Log.d("Library Info", "이름: ${library.library_name}, 주소: ${library.address}")
            }
        } else {
            // API 호출 실패 시 처리 로직을 추가해주세요!
            Log.e("API Error", "Code: ${response.code()}, Message: ${response.message()}")
        }
    } catch (e: Exception) {
        // 네트워크 오류 등 예외 발생 시 처리 로직을 추가해주세요!
        Log.e("Network Error", "Error: ${e.message}")
    }
}

자, 이렇게 하면 전국 도서관 정보를 가져와서 활용할 수 있어요! 참 쉽죠?! API 연동, 이제 어렵지 않아요! 다음에는 더 재밌고 유용한 예제로 찾아올게요! 기대해 주세요! 😉

 

자, 이렇게 Retrofit을 사용해서 Kotlin으로 API 연동하는 방법을 차근차근 살펴봤어요! 어때요, 생각보다 어렵지 않았죠? 처음엔 조금 낯설 수도 있지만, 몇 번 연습하다 보면 금방 익숙해질 거예요. 마치 새로운 친구 사귀는 것처럼 말이죠. Retrofit은 정말 강력하고 편리한 도구라서, 여러분의 개발 생활에 큰 도움이 될 거라고 확신해요. API 연동, 이제 걱정하지 말고 Retrofit과 함께 즐겁게 개발해 보자구요! 앞으로 더 멋진 앱을 만들 여러분을 응원할게요! 혹시 궁금한 점이나 어려운 부분이 있다면 언제든지 댓글 남겨주세요. 함께 고민하고 해결해 나가면 더 재밌을 거예요. 그럼 다음에 또 유익한 정보로 만나요!

 

Leave a Comment