Retrofit
이란 서버와 클라이언트간 http 통신을 위한 라이브러리이다.
더 쉽게 말하자면 안드로이드에서 RESTful
한 http 통신을 할 수 있도록 도와주는 녀석이다.
RESTful 한건 또 뭐냐고..
채용 공고를 조금만 둘러보아도 REST API
를 활용해본자.. 또는 RESTful
한 코드를 작성해본자 이런식의 공고들이 많이 보인다.
위의 정의에서 볼 수 있듯, Retrofit
은 안드로이드에서 RESTful
한 http통신을 돕는 녀석이다. Retrofit
의 이해를 위해선 이 RESTful
하다는 놈의 느낌을 먼저 알고 가야할 것 같다.
이 REST API
라는 것은 정보를 주고받아지는데 있어서 개발자들 사이에서 널리 사용되는 형식같은 것이다.
일단 API
란 녀석부터 이해하고 시작하자.
API
는 위에서 REST API
로 설명한 것과 같다. 개발자들 사이에서 정보를 주고받는데 사용되는 형식같은거다.
요즘은 여러 업체에서 만든 기술들을 무료로 오픈하여 API
로 사용할 수 있게 해주기도 한다.
예를 들어 기상청에서 무료로 제공하는 날씨 API를 예로 들어보자.
각 웹사이트나 앱들이 이 기상청 서버로부터 실시간으로 날씨 정보를 받아갈 수 있다.
이제 여기서 API
의 역할이 나온다. 각 웹사이트나 앱들이 정보를 가져가는데 각자 양식이 제각기로 다르면 정보를 제공하는 서버에서 데이터를 전송해주기 힘들다.
그래서 지정된 형식을 만들어 날씨정보를 활용하고자 하는 사람들이 통일된 형식으로 요쳥, 명령을 받을 수 있도록 만든 수단을 만들었는데, 이것을 바로 API
라고 한다.
이제 API를 알았으니 앞에 붙는
REST
와RESTful
이 뭔지도 알아보자
일단 보는 것처럼 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
을 알아보자Retrofit
은 OkHttp
를 베이스로 만들어졌다.
OkHttp
는 REST API, HTTP
통신을 간편하게 구현할 수 있도록 다양한 기능을 제공하는 라이브러리이고, Retrofit
의 베이스가 된다.
이론은 이쯤 해두고 실제 안드로이드에 적용하는 과정이 궁금해서 찾아보다가
오늘의코드 < 이분의 블로그의 글을 보면서 이해하는데 큰 도움을 얻었다.
한번 따라해보자
통신할 사이트에 들어가서 F12
를 눌러서 개발자 도구로 들어간 뒤,
Network - all
을 클릭하고 ctrl + R
을 눌러주자
괜히 보이면 안될 정보같아서 가렸지만, 밑에 뭔가 쫘르륵 나올 것이다.
그런 다음, 공지사항의 다음 페이지로 넘어가보자
넘어가다보면 위에 초가 나오는 표에 점 같은 것들이 찍혔을텐데, 여기가 게시물 목록이 바뀌는 부분이다.
눌러서 밑에 나오는 녀석들중 공지사항 글이랑 관련있을 것 같은 걸 눌러보면, 원하는 정보를 얻을 수 있을 것 같은 파트가 나온다!
여기서 머리글을 클릭해보면 다음과 같이 요청 URL과 요청 메서드 형태를 얻을 수 있다.
이제 파라미터를 알아내야 하는데 여기엔 POSTMAN
이라는 프로그램을 사용한다.
이렇게 아까 받았던 요청 URL을 POSTMAN
에 넣어주면 이런식으로 파라미터를 보여준다.
하나씩 체크를 풀고 요청을 보내보면서 필수 파라미터를 확인할 수 있다.
이제 파라미터를 얻었으니 안스에서 직접 받아서 사용해볼 순서다.
일단 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¬iceType&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¬iceType&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¬iceType&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 생성
내용 및 사진 출처, 이해를 도와준 분들 🙏 ( 클릭 시 이동됩니다 )