오늘은 Retrofit을 통해 API와 통신하는 기능을 구현해봤습니다. 요즘 CometChat이라는 API를 이용해서 간단한 채팅앱을 구현하는 중인데 아이디로 친구추가하는 기능을 REST API와 통신하는 방식으로 구현하게 되서 이번 포스트를 작성하게 되었습니다.
우선 build.gradle(Module:app) 파일에 다음 dependencies를 추가해줍니다.
implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
implementation 'com.squareup.retrofit2:converter-gson:(insert latest version)'
그 다음 HTTP API를 interface 형태로 만들어 줍니다.
interface CometChatFriendsService {
@Headers("accept: application/json",
"content-type: application/json")
@POST("{version}/users/{uid}/friends")
fun addFriend(@Header("apikey") apiKey: String,
@Header("appid") appID: String,
@Body params: HashMap<String, List<String>>,
@Path("version") version: String,
@Path("uid") uid: String)
: Call<Data>
}
맨 위에 @Headers에는 정적 헤더들을 명시해줍니다.
모든 메소드들은 반드시 상대 URL과 요청 메소드를 명시하는 어노테이션을 가지고 있어야합니다. 전 Post 메소드가 필요해서 @POST를 사용했는데 다른 메소드가 필요하신 분들은 @GET, @DELETE 등으로 대체해서 사용하시면 됩니다.
요청 URL은 동적으로 부분치환이 가능한데, {}안에 있는 부분은 메소드의 매개변수에 명시된 @Path로 변경이 가능합니다.
요청 메소드인 addFriend의 매개변수에는 동적인 헤더를 명시하는 @Header, 해당 POST 메소드에서 요구하는 정보를 담고 있는 @Body, URL의 부분치환할 부분을 담고 있는 @Path 어노테이션이 있습니다.
참고로 헤더를 모든 요청마다 추가하셔야 한다면 OkHttp interceptor 사용을 권장합니다.
위의 요청 메소드를 Talend API Tester로 만들면 이런 모습이 되겠네요.
제가 이 요청을 통해 받을 데이터는 아래와 같은 형태인데요.
"data":{
"accepted":{
"superhero3":{
"success": true,
"message": "Updated relationship status to accepted."
},
"superhero4":{
"success": true,
"message": "Updated relationship status to accepted."
}
}
}
이 데이터를 파싱하기 위한 data class들을 만들겠습니다.
data class Data(val data: Accepted)
data class Accepted(val accepted: HashMap<String, Friend>)
data class Friend(val success: Boolean, val message: String)
그 다음 Retrofit 객체를 생성해주고 생성한 객체를 통해 아까 만든 interface를 구현하여 생성해줍니다. 그리고 Body에 넣을 데이터를 HashMap형태로 만들어준뒤 서비스의 addFriend 메소드를 불러줍니다.
//Retrofit 객체 생성
val retrofit = Retrofit.Builder()
.baseUrl(this.URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
//retrofit 객체를 통해 인터페이스 생성
val service = retrofit.create(CometChatFriendsService::class.java)
//Body에 담을 데이터 생성
val friends = ArrayList<String>()
friends.add(friendID)
val body = HashMap<String, List<String>>()
body.put("accepted", friends)
service.addFriend(context.getString(R.string.apiKey), context.getString(R.string.appID),
body, version, uid)?.enqueue(object : Callback<Data> {
override fun onFailure(call: Call<Data>, t: Throwable) {
Log.d("CometChatAPI::", "Failed API call with call: " + call +
" + exception: " + t)
}
override fun onResponse(call: Call<Data>, response: Response<Data>) {
Log.d("Response:: ", response.body().toString())
val friends = response.body()!!.data.accepted
Log.d("Friends:: ", friends.toString())
for (friendName in friends.keys) {
Log.d("${friendName}:: ", friends[friendName].toString())
}
}
})
위 코드를 실행한뒤 로그캣을 확인해보니 아래와 같은 응답을 받을수 있네요.
D/Response::: Data(data=Accepted(accepted={superhero3=Friend(success=true, message=Updated relationship status to accepted.)}))
D/Friends::: {superhero3=Friend(success=true, message=Updated relationship status to accepted.)}
D/superhero3::: Friend(success=true, message=Updated relationship status to accepted.)
끝으로 네트워킹을 하기 때문에 Manifest파일에 인터넷 사용 퍼미션을 추가하는 것도 잊으시면 안됩니다.
제가 Kotlin 관련 글을 찾다가 벨로그로 돌아올줄이야..! ㅋㅋㅋ
저도 개발하면서 배운것들을 좀 정리해야겠습니다 .
잘 읽고가요~