Retrofit 개념

2024. 7. 31. 21:32[개발]/Kotlin 활용 앱 개발

# 서버와 클라이언트

- 서버: 데이터나 리소스를 제공하는 시스템

- 클라이언트: 유저를 대표해 서버에 정보나 서비스를 요청하는 시스템

 

# 프로토콜

- 클라이언트가 서버에 무언가를 요청할 때 정해놓은 통신 규약(약속)

- 웹 어플리케이션 프로토콜: HTTP

 

# API

- 클라이언트가 서버에 무언가를 요청할 때, 서버가 클라이언트에게 리소스를 잘 활용할 수 있도록 제공해주는 인터페이스(메뉴판)

 

# REST API(REpresentational State Transfer)

- 웹에서 서버와 클라이언트 간의 통신을 위한 표준 방법

- 웹에서 데이터를 주고받는 방법을 정의

- 클라이언트가 서버에 정보를 요청하고, 서버가 그 정보를 제공

- 구성 요소

① URL 엔드포인트: 웹상의 자원을 나타내는 URL 링크

② HTTP 동사(C R U D / Create Read Update Delete): 서버에게 리소스에 대해 수행하고자 하는 동작을 알리는 방법

* 주요 HTTP 동사: GET(기존 리소스 조회), POST(새 리소스 생성), DELETE(리소스 삭제), PUT(기존 리소스 업데이트)

③ 본문(Body): 선택적인 사용자 정의 데이터로, 생성 또는 업데이트하려는 리소스의 속성과 값이 포함

- 하지만 안드로이드는 JSON이 뭔지, HTTP가 뭔지,,, 알지를 못함

 

# JSON

- 데이터를 저장하거나 전송할 때 많이 사용되는 경량의 DATA 교환 형식

- 하나의 데이터는 하나의 NAME, 하나의 VALUE로 구성

- 중괄호로 표현(리스트 - 대괄호)

// 예시
{
  "이름": "뚱이1",
  "몸무게": "80kg",
  "목표몸무게":"79kg",
  "식단": [
    {
      "아침": "샐러드",
      "점심": ["김치찌개", "콩나물", "감자"],
			"저녁": ["돼지갈비", "탕수육", "라면"]
    },
    {
      "아침": "족발",
      "점심": ["치킨", "보쌈", "감자"],
			"저녁": "탕후루"
    },
    {
      "아침": "고구마",
      "점심": ["옥수수", "콩나물", "쌀국수"],
			"저녁": ["삼겹살", "짜장면", "라면"]
    }
  ]
}

 

# GSON

- Google에서 제공하는 Java 오픈소스 라이브러리

- JSON 데이터를 코틀린 객체로 변환(역직렬화(Deserialization))하거나, 반대로 변환(직렬화(Serialilzation))할 때 수행하는  작업을 간단하게 해줌

① 직렬화

val gson = Gson()
val jsonString = gson.toJson(someObject)

② 역직렬화

val myClassInstance: MyClass = gson.fromJson(jsonString, MyClass::class.java)

- @SerializedName 어노테이션: Kotlin 필드와 JSON 키 이름이 다를 경우 매핑(JSON 데이터는 이름에 언더바(_)를 잘 쓰는 반면, 코틀린에서는 카멜 표기법을 주로 사용하므로 달라질 수 있음)

data class Person(
    @SerializedName("channel_title")
    val channelTitle: String
    @SerializedName("channel")
    val channel : String
)

 

 

 

 

# Retrofit

- 옛날의 언어를 사용하는 서버(Retro)와 안드로이드 클라이언트가 잘 소통(Fit)할 수 있도록 도와주는 HTTP 클라이언트 라이브러리

- Rest API의 HTTP 요청을 자바 인터페이스로 변환

- Retrofit의 장점

① 코드의 간결성

② 안정성과 확장성

③ 다양한 플러그인과 컨버터 지원

 

# Retrofit 사용 방법

1) Gradle에 라이브러리 추가

dependencies {
    // Retrofit
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    // Gson Converter
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    // OKHttp for 통신 로그
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")

 

***** 2) API 인터페이스 정의: 서비스의 각 HTTP 엔드포인트에 대해 메서드를 정의하는 인터페이스 생성 *****

interface YoutubeAPI {
    @GET("videos")
    suspend fun getTrendingVideos(
        @Query("part") part: String = "snippet",
        @Query("chart") chart: String = "mostPopular",
        @Query("maxResults") maxResults: Int = 100,
        @Query("regionCode") regionCode: String = "US",
        @Query("key") apiKey: String = API_KEY
    ): VideoResponse
}

 

3) Retrofit 인스턴스 생성: Retrofit Builder를 사용해 인스턴스를 생성, BaseURL과 Data Converter를 설정

import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create

object RetrofitClient {
    private const val BASE_URL = "https://www.googleapis.com/youtube/v3/"

    private val retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(
                OkHttpClient.Builder()
                    .addInterceptor(HttpLoggingInterceptor().apply {
                        level = HttpLoggingInterceptor.Level.BODY
                    }).build()
            )
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    val youtubeAPI: YoutubeAPI by lazy { retrofit.create() }
}

 

4) API 호출: 인터페이스를 통해 API를 호출하고 응답을 처리

  override suspend fun getTrendingVideos(region: String): VideoResponse {
        return RetrofitClient.youtubeAPI.getTrendingVideos(regionCode = region)
    }
}

 

5) 인터넷 권한 추가

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

// 보안에 취약한 HTTP 네트워크 트래픽도 사용할 수 있도록 설정
android:usesCleartextTraffic="true"

 

 

 

 

 

 

 

 

interface YoutubeAPI {
	// 사이트 url?
    @GET("videos")
    suspend fun getTrendingVideos(
    	// Youtube API 사이트 참고 - part: 필수 / 나머지: 선택
        @Query("part") part: String = "snippet",
        @Query("chart") chart: String = "mostPopular",
        @Query("maxResults") maxResults: Int = 100,
        @Query("regionCode") regionCode: String = "US",
        @Query("key") apiKey: String = API_KEY
    ): VideoResponse
}
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create

object RetrofitClient {
    private const val BASE_URL = "https://www.googleapis.com/youtube/v3/"

    private val retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            // 데이터 가져올 때 오류가 나면 로그를 찍어주는 역할
            .client(
                OkHttpClient.Builder()
                    .addInterceptor(HttpLoggingInterceptor().apply {
                        level = HttpLoggingInterceptor.Level.BODY
                    }).build()
            )
            // Google에서 만든 JSON 형식 컨버터 = GsonConverterFactory
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    val youtubeAPI: YoutubeAPI by lazy { retrofit.create() }
}
<uses-permission android:name="android.permission.INTERNET" />

// 보안처리가 안된 http 사이트를 가져오기 위해 추가해야 하는 코드
android:usesCleartextTraffic="true"