본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
앱과 서버의 비밀 통로 '네트워크'와 'Retrofit'으로 API 정복!

안녕하세요, 여러분! ✨
지난 시간에는 자바의 강력한 데이터 처리 도구 '스트림(Stream)' 🌊 에 대해 배우면서, 복잡한 데이터 가공을 마치 물 흐르듯 우아하게 처리하는 마법을 경험했죠! 람다와 스트림의 조합은 정말이지 코드를 간결하고 명확하게 만들어주는 환상의 짝꿍이었습니다! 👍
하지만 우리가 만드는 앱들은 대부분 혼자 존재하지 않죠. 최신 뉴스 헤드라인을 보여주거나, 친구의 소셜 미디어 피드를 가져오거나, 온라인 게임 서버에 접속하는 등, 앱은 종종 외부 세계(서버!) 와 소통해야 합니다. "다른 컴퓨터에 있는 데이터를 어떻게 가져오지? 🤔", "내가 만든 앱의 데이터를 서버에 어떻게 보내지? 📤", "이 복잡해 보이는 통신 과정을 좀 더 쉽게 할 순 없을까? 🤯" 이런 고민, 앱 개발을 하다 보면 반드시 마주치게 됩니다.
특히 안드로이드에서 네트워크 통신 코드를 직접 작성하려면, 생각보다 많은 예외 처리와 스레드 관리 등 신경 써야 할 부분이 많답니다. 마치 외국어로 된 복잡한 문서를 번역기 없이 직접 해석하려는 것과 같죠. 😵
오늘은 바로 이런 앱과 서버 간의 소통(네트워크 통신) 의 기본 개념을 이해하고, 이 과정을 혁신적으로 간편하게 만들어주는 강력한 라이브러리, Retrofit 사용법을 배워볼 시간입니다! 💻➡️☁️ 마치 능숙한 통역사(Retrofit)를 고용해 외국(서버)과의 소통 장벽을 허무는 것과 같아요! 🗣️🤝
오늘 우리가 탐험할 네트워크 통신의 세계는 다음과 같아요:
- 앱들의 소통 방식 - 네트워크 기초 & API란? (🌐🤝📜) (서버와 대화하는 법!)
- 왜 Retrofit인가? (Why Retrofit?) <✨> (코드 간소화의 마법!)
- Retrofit 핵심 탐험: 설정부터 호출까지! (Retrofit in Action) <🛠️➡️🚀> (실전! API 호출하기!)
자, 앱의 경계를 넘어 서버와 데이터를 주고받을 준비, 되셨나요? 함께 네트워크와 Retrofit의 세계로 떠나봅시다! 🚀

1. 앱들의 소통 방식 - 네트워크 기초 & API란? (🌐🤝📜)
우리가 스마트폰 앱을 사용할 때, 화면에 보이는 정보들은 대부분 앱 자체에 저장된 것이 아니라 서버(Server) 라는 다른 컴퓨터에서 가져온 경우가 많습니다. 우리 앱(스마트폰)은 클라이언트(Client) 가 되어 서버에게 "이런 정보 좀 주세요!" 또는 "이 데이터 좀 저장해주세요!" 라고 요청(Request) 을 보내고, 서버는 그 요청을 처리한 후 응답(Response) 을 보내주는 방식이죠. 마치 식당에서 손님(클라이언트)이 메뉴판(API)을 보고 주문(요청)하면, 주방(서버)에서 요리(데이터 처리)를 해서 음식을 내어주는(응답) 것과 비슷해요! 🍽️
이때, 클라이언트와 서버가 서로 '어떻게' 요청하고 응답할지 정해놓은 규칙과 메뉴판 같은 역할을 하는 것이 바로 API (Application Programming Interface) 입니다. 웹 환경에서는 주로 HTTP(HyperText Transfer Protocol) 라는 통신 규약을 사용하며, "어떤 주소(URL)로", "어떤 방식(GET, POST 등)으로", "어떤 데이터 형식(주로 JSON)으로" 요청하고 응답할지가 API 명세에 정의되어 있죠.
- HTTP 메서드 (대표적인 예시):
- GET: 서버로부터 데이터를 조회할 때 사용 (ex: 뉴스 목록 가져오기)
- POST: 서버에 새로운 데이터를 생성/전송할 때 사용 (ex: 회원가입 정보 보내기)
- PUT: 기존 데이터를 수정할 때 사용 (ex: 프로필 정보 업데이트)
- DELETE: 기존 데이터를 삭제할 때 사용 (ex: 게시글 삭제)
- JSON (JavaScript Object Notation): 서버와 클라이언트가 데이터를 주고받을 때 가장 널리 사용하는 텍스트 기반의 데이터 형식입니다. { "key": "value" } 와 같이 사람이 읽고 쓰기 쉬우면서도 기계가 파싱하기 좋은 형태죠.
즉, 네트워크 통신은 우리 앱이 HTTP라는 언어를 사용해, 정해진 API 규칙에 따라 서버와 JSON 같은 형식으로 데이터를 주고받는 과정이라고 이해할 수 있습니다!
2. 왜 Retrofit인가? (Why Retrofit?) <✨> (코드 간소화의 마법!)
"그럼 그냥 안드로이드에서 제공하는 기본 기능으로 HTTP 통신하면 안 되나요?" 물론 가능합니다! 하지만 HttpURLConnection 같은 기본적인 API를 사용하면 다음과 같은 번거로움이 따릅니다.
- 연결 설정, 데이터 송수신, 스트림 처리 등 반복적인 코드(Boilerplate code) 가 많아집니다.
- 네트워크 작업은 백그라운드 스레드에서 처리해야 하므로 스레드 관리가 복잡합니다. (UI 스레드에서 직접 네트워크 요청하면 앱이 멈춰버려요! 🥶)
- JSON 데이터를 객체로 변환하거나, 객체를 JSON으로 변환하는 파싱(Parsing) 코드를 직접 작성해야 합니다.
- 에러 처리가 까다롭습니다.
이런 어려움들을 해결해주기 위해 등장한 라이브러리가 바로 Retrofit 입니다! 마치 복잡한 서류 작업을 대신 처리해주는 유능한 비서와 같죠. 🧑💼✨ Retrofit을 사용하면 다음과 같은 놀라운 이점들을 얻을 수 있습니다.
- 선언적 API 정의: 마치 인터페이스에 메서드를 선언하듯이, 어노테이션(@GET, @POST 등)을 사용해 API 호출 방식을 깔끔하게 정의할 수 있습니다. '어떻게' 통신할지가 아닌, '무엇을' 요청할지에 집중하게 되죠! (스트림의 선언적 프로그래밍과 비슷하죠? 😉)
- 타입 안전성 (Type Safety): 요청과 응답 데이터 타입을 명확하게 지정하여 컴파일 시점에 오류를 잡을 가능성이 높아집니다.
- 간편한 JSON 파싱: Gson, Moshi 같은 라이브러리와 쉽게 통합되어 JSON 데이터를 Java/Kotlin 객체로 자동 변환해줍니다.
- 쉬운 비동기 처리: enqueue 메서드를 사용하거나, 코루틴(Coroutine)과 함께 사용하면 복잡한 스레드 관리 없이 비동기 호출을 손쉽게 구현할 수 있습니다.
결론적으로, Retrofit은 안드로이드에서 네트워크 통신 코드를 훨씬 간결하고, 안전하고, 효율적으로 작성할 수 있도록 도와주는 필수 라이브러리라고 할 수 있습니다! 👍
3. Retrofit 핵심 탐험: 설정부터 호출까지! (Retrofit in Action) <🛠️➡️🚀>
자, 이제 실제로 Retrofit을 사용하여 간단한 API를 호출하는 과정을 단계별로 살펴봅시다! (예시는 Kotlin 기준으로 작성되었지만, Java에서도 유사하게 사용 가능합니다.)

Step 1: 라이브러리 추가 (build.gradle)
먼저 app/build.gradle 파일에 Retrofit과 Gson 변환기 라이브러리 의존성을 추가합니다.
dependencies {
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0' // 최신 버전 확인 필요
// Gson Converter (JSON <-> 객체 변환)
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// (선택) 로깅 인터셉터 (네트워크 통신 로그 확인용)
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
}
(주의!) 네트워크 통신을 위해서는 AndroidManifest.xml 파일에 인터넷 사용 권한을 추가해야 합니다!
<uses-permission android:name="android.permission.INTERNET" />
Step 2: 데이터 모델 정의 (DTO/VO)
서버로부터 받을 JSON 데이터 구조에 맞춰 Kotlin의 data class (또는 Java의 POJO 클래스)를 정의합니다. 예를 들어 사용자 정보를 받는다면:
data class User(
val id: Int,
val name: String,
val username: String,
val email: String
)
Step 3: API 인터페이스 정의
호출할 API 엔드포인트들을 정의하는 인터페이스를 만듭니다. 각 메서드에는 HTTP 메서드 어노테이션(@GET, @POST 등)과 경로(URL의 뒷부분)를 지정합니다.
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
interface ApiService {
// 예시: https://jsonplaceholder.typicode.com/users/1 과 같은 API 호출
@GET("users/{userId}") // HTTP GET 요청, 경로 변수 {userId} 사용
fun getUser(@Path("userId") id: Int): Call<User> // 경로 변수에 id 값을 넣어 호출, 응답은 User 객체로 받음
// 예시: 모든 사용자 목록 가져오기
@GET("users")
fun getUsers(): Call<List<User>> // 응답은 User 객체의 리스트로 받음
}
Call<T>은 Retrofit에서 API 호출을 나타내는 타입이며, T는 응답받을 데이터 모델입니다.
Step 4: Retrofit 인스턴스 생성
앱 전체에서 재사용할 수 있도록 Retrofit 객체를 생성하는 싱글턴(Singleton) 객체나 의존성 주입(DI)을 사용하는 것이 좋습니다.
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
private const val BASE_URL = "https://jsonplaceholder.typicode.com/" // API 서버의 기본 URL
val instance: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) // Gson 변환기 사용 설정
.build()
}
val apiService: ApiService by lazy {
instance.create(ApiService::class.java)
}
}
Step 5: API 호출 및 응답 처리
이제 생성된 Retrofit 인스턴스와 API 인터페이스를 사용하여 실제 API를 호출합니다. 비동기 방식인 enqueue를 사용하는 예시입니다.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) // 레이아웃 설정
// 사용자 정보 가져오기 (예: ID가 1인 사용자)
fetchUserData(1)
}
private fun fetchUserData(userId: Int) {
// Step 4에서 만든 RetrofitClient 사용
RetrofitClient.apiService.getUser(userId).enqueue(object : Callback<User> {
// 요청 성공 시
override fun onResponse(call: Call<User>, response: Response<User>) {
if (response.isSuccessful) {
val user = response.body() // 응답 본문(User 객체) 가져오기
if (user != null) {
Log.d("MainActivity", "사용자 정보: ${user.name}, ${user.email}")
// TODO: 가져온 사용자 정보로 UI 업데이트 등
}
} else {
Log.e("MainActivity", "응답 실패: ${response.code()}")
// TODO: 서버 에러 처리 (404 Not Found, 500 Internal Server Error 등)
}
}
// 요청 실패 시 (네트워크 연결 오류 등)
override fun onFailure(call: Call<User>, t: Throwable) {
Log.e("MainActivity", "네트워크 오류: ${t.message}")
// TODO: 네트워크 오류 처리
}
})
}
}
enqueue 메서드는 백그라운드 스레드에서 네트워크 요청을 실행하고, 결과를 메인 스레드에서 처리할 수 있도록 콜백(onResponse, onFailure)을 제공합니다. 이제 우리는 복잡한 스레드 관리나 JSON 파싱 코드 없이도 서버와 깔끔하게 통신할 수 있게 되었습니다! 🎉
정리하며 📝
오늘은 앱 개발의 필수 요소인 네트워크 통신의 기본 개념과 Retrofit 라이브러리 사용법에 대해 알아보았습니다! 🌐
- 네트워크 통신: 클라이언트(앱)와 서버가 HTTP 프로토콜과 API 규칙에 따라 데이터를 주고받는 과정.
- API: 앱과 서버가 소통하기 위한 약속/메뉴판. HTTP 메서드(GET, POST 등)와 데이터 형식(주로 JSON) 등을 정의.
- Retrofit: 안드로이드에서 네트워크 통신을 매우 간편하게 만들어주는 라이브러리.
- 선언적 인터페이스 정의로 코드 간결화 ✨
- 타입 안전성 제공 👍
- Gson 등과 연동하여 쉬운 JSON 파싱 ✅
- enqueue 또는 코루틴으로 간편한 비동기 처리 🚀
- Retrofit 사용 단계: 의존성 추가 → 데이터 모델 정의 → API 인터페이스 정의 → Retrofit 인스턴스 생성 → API 호출 및 응답 처리.

스트림이 앱 내부의 데이터 흐름을 우아하게 만들었다면, Retrofit은 앱 외부(서버)와의 데이터 흐름을 매끄럽게 만들어주는 강력한 도구입니다. 이제 여러분의 앱은 더 넓은 세상과 소통할 수 있는 능력을 갖추게 되었어요! 직접 간단한 무료 API(JSONPlaceholder 같은)를 찾아서 Retrofit으로 호출해보는 연습을 꼭 해보시길 바랍니다! 😊
'데이터 엔지니어링' 카테고리의 다른 글
| 패스트캠퍼스 환급챌린지 37일차: 데이터엔지니어링 초격차 강의 후기 (0) | 2025.05.07 |
|---|---|
| 패스트캠퍼스 환급챌린지 36일차: 데이터엔지니어링 초격차 강의 후기 (0) | 2025.05.06 |
| 패스트캠퍼스 환급챌린지 34일차: 데이터엔지니어링 초격차 강의 후기 (0) | 2025.05.04 |
| 패스트캠퍼스 환급챌린지 33일차: 데이터엔지니어링 초격차 강의 후기 (3) | 2025.05.03 |
| 패스트캠퍼스 환급챌린지 32일차: 데이터엔지니어링 초격차 강의 후기 (0) | 2025.05.02 |