[Android] Retrofit, REST API.. 그게뭔데

moKo·2022년 4월 20일
1

Android

목록 보기
9/13
post-thumbnail

Retrofit ?

Retrofit이란 서버와 클라이언트간 http 통신을 위한 라이브러리이다.
더 쉽게 말하자면 안드로이드에서 RESTful한 http 통신을 할 수 있도록 도와주는 녀석이다.

RESTful 한건 또 뭐냐고..

채용 공고를 조금만 둘러보아도 REST API를 활용해본자.. 또는 RESTful한 코드를 작성해본자 이런식의 공고들이 많이 보인다.

위의 정의에서 볼 수 있듯, Retrofit은 안드로이드에서 RESTful한 http통신을 돕는 녀석이다. Retrofit의 이해를 위해선 이 RESTful하다는 놈의 느낌을 먼저 알고 가야할 것 같다.

REST API, RESTful API

REST API 라는 것은 정보를 주고받아지는데 있어서 개발자들 사이에서 널리 사용되는 형식같은 것이다.

일단 API란 녀석부터 이해하고 시작하자.

API는 위에서 REST API로 설명한 것과 같다. 개발자들 사이에서 정보를 주고받는데 사용되는 형식같은거다.

요즘은 여러 업체에서 만든 기술들을 무료로 오픈하여 API로 사용할 수 있게 해주기도 한다.

예를 들어 기상청에서 무료로 제공하는 날씨 API를 예로 들어보자.
각 웹사이트나 앱들이 이 기상청 서버로부터 실시간으로 날씨 정보를 받아갈 수 있다.

이제 여기서 API의 역할이 나온다. 각 웹사이트나 앱들이 정보를 가져가는데 각자 양식이 제각기로 다르면 정보를 제공하는 서버에서 데이터를 전송해주기 힘들다.

그래서 지정된 형식을 만들어 날씨정보를 활용하고자 하는 사람들이 통일된 형식으로 요쳥, 명령을 받을 수 있도록 만든 수단을 만들었는데, 이것을 바로 API라고 한다.

이제 API를 알았으니 앞에 붙는 RESTRESTful이 뭔지도 알아보자

일단 보는 것처럼 REST라는 형식의 API를 말한다.

REST의 가장 중요한 특성은 각 요청이 어떤 동작이나 정보를 위한 것인지 그 요청의 모습 자체로 추론이 가능하다는 것이다.

그럼 REST API는 뭘까?

요청을 보내는 주소만으로도 대략 이게 뭘 원하는 요청인지를 알아볼 수 있도록 만든 API다.

학원API를 예를 들어보자.

https://도메인/classes 이런식의 요청을 보내면 이건 학원의 클래스 정보를 받아오는 것임을 한눈에 알 수 있다.

https://도메인/classes/2/students 이 요청은 2번 클래스에 해당하는 학생들의 정보를 받아오는 것이다.

이런식으로 자원을 구조와 함께 나타내는 이런 형태의 구분자를 URI라고 한다.

근데 이런식의 조회뿐만 아니라 수정, 삭제, 삽입하는 작업 또 필요할텐데, 이런 작업들을 통틀어서 C.R.U.D라고 부른다.

C = CREATE/생성 , R = READ/조회 , U = UPDATE/수정 , D = DELETE/삭제

서버에 REST API로 요청을 보낼 때는 HTTP라는 규약에 따라 신호를 전송한다.

HTTP로 요청을 보낼때도 여러 메소드가 있는데 REST API에서는 GET, POST, DELETE, PUT 이렇게 네 가지의 메소드를 주로 사용한다.

이 메소드들도 각자 사용하는 목적이 있다.

  • GET : 데이터를 READ, 조회하는데 사용한다.
    [GET] https://도메인/classes/2/students 는 2반의 학생들을 조회하는 요청이다.

  • POST : 데이터를 CREATE, 새로운 정보를 추가하는데 사용한다.
    [POST] https://도메인/classes/2/students 한 후 추가할 정보를 담는 BODY{"idx" : 12, "name" : "최민수", "sex" : "male"}, 이런식으로 정보를 담아서 보내주면 된다.

  • PUT : 데이터를 UPDATE, 수정하는데 사용한다.
    [PUT] https://도메인/classes/2/students/15 (15번 인덱스로 변경) 한 후 수정할 정보를 담는 BODY{"idx" : 15, "name" : "최민수", "sex" : "male"}, 이런식으로 정보를 담아서 보내주면 된다.

  • DELETE : 데이터를 DELETE, 삭제하는데 사용한다.
    [DELETE] https://도메인/classes/2/students/15 는 15번 인덱스의 학생을 삭제하는 요청이다.

이쯤되면 REST API에 대해선 어느정도 이해를 한 것 같다.

이제 다시 한번 Retrofit을 알아보자

RetrofitOkHttp를 베이스로 만들어졌다.

OkHttpREST API, HTTP통신을 간편하게 구현할 수 있도록 다양한 기능을 제공하는 라이브러리이고, Retrofit의 베이스가 된다.

이론은 이쯤 해두고 실제 안드로이드에 적용하는 과정이 궁금해서 찾아보다가
오늘의코드 < 이분의 블로그의 글을 보면서 이해하는데 큰 도움을 얻었다.

한번 따라해보자

통신할 사이트에 들어가서 F12를 눌러서 개발자 도구로 들어간 뒤,
Network - all 을 클릭하고 ctrl + R을 눌러주자

괜히 보이면 안될 정보같아서 가렸지만, 밑에 뭔가 쫘르륵 나올 것이다.

그런 다음, 공지사항의 다음 페이지로 넘어가보자

넘어가다보면 위에 초가 나오는 표에 점 같은 것들이 찍혔을텐데, 여기가 게시물 목록이 바뀌는 부분이다.

눌러서 밑에 나오는 녀석들중 공지사항 글이랑 관련있을 것 같은 걸 눌러보면, 원하는 정보를 얻을 수 있을 것 같은 파트가 나온다!

여기서 머리글을 클릭해보면 다음과 같이 요청 URL과 요청 메서드 형태를 얻을 수 있다.

이제 파라미터를 알아내야 하는데 여기엔 POSTMAN 이라는 프로그램을 사용한다.

이렇게 아까 받았던 요청 URL을 POSTMAN에 넣어주면 이런식으로 파라미터를 보여준다.
하나씩 체크를 풀고 요청을 보내보면서 필수 파라미터를 확인할 수 있다.

Android Studio Setting

이제 파라미터를 얻었으니 안스에서 직접 받아서 사용해볼 순서다.
일단 Retrofit의 Gradle부터 세팅을 해줘야 한다.

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

Manifest에 permission 설정을 해주자

<uses-permission android:name="android.permission.INTERNET"/>
 // 서버 통신을 위한 인터넷 권한

그리고 application 단 안쪽에 아래의 코드를 넣어주자

android:usesCleartextTraffic="true"
// http로 시작되는 사이트에 접근하기 위함

이제 data class를 작성해보자

JSON 형식이니 여기에 맞추어 작성해야한다.

이걸 정리해보면 다음과 같다.

응답 결과
└ timestamp
└ statusCode
└ statusMessage
└ data
    └ content[0] // '{'가 아닌 '['로 시작했다는 건 배열이란 뜻
        └ contentId
        └ contentSeq
        └ title
        └ content

이걸 안스에서 data class로 나타내면 이런식이다.

data class Baemin(val timestamp: Long, val statusCode: String, val statusMessage: String, val data: Data)
 
data class Data(val content: ArrayList<Content>) // 배열이기에 ArrayList로
 
data class Content(val contentId: Long, val contentSeq: Long, val title: String, val created: String)

만약 변수명이 맘에 들지 않는다면 @SerializedName으로 바꿀 수 있다고 한다.

data class Content(
    @SerializedName("title")
    val title: String,
    @SerializedName("created")
    val date: String
)

다음으론 Interface를 정의해야 한다. 아래 코드를 하나하나 이해해보자.

interface BaeminService {
    @GET("contents?sort=startDisplayTime,desc&typeCode=notice&size=
    10&noticeType&page=3&__ts=1650445180082")
    fun loadNotice(@Query("page") page: String): Call<Baemin>
}

@GET은 아까 개발자도구에서 확인했던 요청 메소드 형태가 @GET이었기때문에 똑같이 사용한다.

그 뒤 괄호안에 있는 것은 END POINT인데, 요청 URL의 링크 마지막의 "/"를 기준으로 그 뒤를 END POINT로 판단한다고 한다.

내 요청 URL이

https://ceo.baemin.com/cms/v1/contents?sort=startDisplayTime,desc&typeCode=notice&size=10&noticeType&page=3&__ts=1650445180082

이었기 때문에 /cms/v1/ < 이 마지막 "/"를 기준으로 뒤에 부분을 넣은 것이다.

fun loadNotice(@Query("page") page: String): Call<Baemin>

배민 공지사항 사이트에서 size와 같은 파라미터는 항상 고정되어 있는 값이다. (항상 한 페이지에 10개의 게시물을 보여주니까!)

하지만 page처럼 값을 동적으로 변경해야 하는 파라미터는 @Query 어노테이션을 이용해서 메서드를 호출할 때 값을 넘겨받아 주소에 포함시켜야 한다

@POST 요청 시에는 방식이 다르다.

interface BaeminService {
 
    @FormUrlEncoded
    @POST("contents?sort=startDisplayTime,desc&typeCode=notice&size=
    10&noticeType&page=3&__ts=1650445180082")
    fun loadNotice(@FieldMap fields: MutableMap<String, String>): Call<Baemin>
}

GET 요청과 달리 POST 요청은 주소에 파라미터가 노출되지 않는다는 특징이 있기 때문에
위와 같이 모든 파라미터를 @FieldMap 어노테이션을 이용해 보내준다.
이때 @FormUrlEncoded로 같이 사용해주어야 한다.

Call<Baemin>Baemin은 아까 만든 Data class 이름을 적은 것이다.

Retrofit의 객체를 생성하자

object BaeminClient {
    private const val baseUrl = "https://ceo.baemin.com/cms/v1/"
    // baseUrl은 아까 end point 앞부분이다.
    private val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
 
    val service = retrofit.create(BaeminService::class.java)!!
}
  • addConverterFactory() : 데이터를 파싱 할 converter를 추가하는 메서도이다. JSON과 같은 데이터는 자바나 코틀린에서 바로 사용할 수 있는 형태가 아니기에 이를 변환해주기위해 converter가 필요하다

HTTP 요청과 응답

class BaeminRepository {
 
    fun loadBaeminNotice(page: Int, mCallback: MainActivity) {
        val call = BaeminClient.service.loadNotice(page.toString())
 
        call.enqueue(object : Callback<Baemin> {  // enqueue : 비동기, execute : 동기
            override fun onResponse( // 통신에 성공한 경우
                call: Call<Baemin>,
                response: Response<Baemin>
            ) {
                if(response.isSuccessful()){ // 응답을 잘 받은 경우
                    mCallback.loadComplete(response.body()!!.data)
                } else {
                    // 통신은 성공했지만 응답에 문제가 있는 경우
                }
            }
 
            override fun onFailure(call: Call<Baemin>, t: Throwable) {
                // 통신에 실패한 경우
            }
        })
    }
}

순서 간단 정리해보기

api 선정 - retrofit gradle set - gradle.properties에 인증키넣고 gradle에 buildconfig 추가 - data 패키지 만들고 baseUrl object 생성 - models 패키지 만들고 api document에 있는 json 파일 받아서 kotlin data class from json으로 data class 생성 - apiservice interface (@get, @query) 작성 - Repository object로 retrofit + okhttpinterceptor 생성


내용 및 사진 출처, 이해를 도와준 분들 🙏 ( 클릭 시 이동됩니다 )

profile
🔥 Feelings fade, results remain

0개의 댓글