개발린생

[Android/Kotlin] API Response 공통 필드 효율적으로 처리하기 본문

Dev Lab ✧.·˚/Android & iOS

[Android/Kotlin] API Response 공통 필드 효율적으로 처리하기

김블루 2024. 11. 28. 23:51

신규 프로젝트 진행, 나는 효율적인 개발을 위해 한 API를 공들여 붙였다!

 

API 호출 후 응답 데이터 관련 주제이며 모든 Response의 값에서 공통으로 들어가는 필드에 대해 효율적으로 처리하는 방법을 공유하고자한다.

 

예시로 쓰일 API 호출, 응답 데이터는 아래와 같다.

 

유저 로그인 API

Request

{
  "id": "blueland", // 유저 로그인 시 아이디
  "password": "qwer1234" // 유저 로그인 시 비밀번호
}

 

Response

{
  "userId": "B0001", // 로그인 된 유저 식별자
  "resultCode": "0000", // 응답 코드
  "resultMessage": "사용자 로그인 성공" // 응답 메세지
}

 

 

유저 정보 조회 API

Request

{
  "userId": "B0001" // 정보를 조회할 유저 식별자
}

 

Response

{
  "userId": "B0001", // 유저 식별자
  "name": "김블루", // 유저 이름
  "phone": "010-1234-5678", // 유저 전화번호
  "email": "blueland@blueland.com", // 유저 이메일 주소
  "resultCode": "0000", // 응답 코드
  "resultMessage": "사용자 정보 조회 성공" // 응답 메세지
}

 

새 프로젝트를 진행하며 서버 개발자로 부터 제공받은 API는 위와 같은 형태였다.

Request 값은 특별한게 없고, Response 값은 resultCode와 resultMessage가 공통으로 들어간다.

이 외에 적용할 다른 API도 resultCode와 resultMessage가 공통으로 내려오는 상황이다.

 

 

우선 Response 객체 코드를 작성해보자

 

 

유저 로그인 API 응답 객체

data class LoginResponse(
    val userId: String,
    val resultCode: String,
    val resultMessage: String
)

 

유저 정보 조회 API 응답 객체

data class UserInfoResponse(
    val userId: String,
    val name: String,
    val phone: String,
    val email: String,
    val resultCode: String,
    val resultMessage: String
)

 

API 응답 값을 받아서 처리하기 위해서는 위와 같이 data class를 생성해줘야한다.

그치만 모든 API에서 resultCode, resultMessage가 내려오니 다른 API 응답 값을 받기위한 data class를 생성할때도 resultCode, resultMessage 필드를 모두 추가해줘야한다.

 

어떻게 보면 별거 아닌 부분이다.

만약 서버 개발자가 어느순간 resultCode를 resultCd, resultMessage를 resultMsg로 바꿔서 내려준다면..?

전체 검색으로 resultCode -> resultCd, resultMessage -> resultMsg로 전체 Replace를 해주면된다.

(위 코드처럼 작성돼있다면 이렇게 처리하면 된다는 것이지, 그닥 권장하진 않음)

 

하지만 공통된 필드가 한 두개가 아니라면?

그것도 머.. 필드마다 검색해서 Replace 해주면 되긴하다..

 

요약하자면, 위 data class 처럼 생성하면 공통 필드가 추가되거나 변경될 때 모든 데이터 클래스를 수정해야 하는 번거로움이 생긴다.

그리하여 공통 필드가 추가되거나 변경될 때 한 곳에서만 수정할 수 있는 방법을 적어보겠다.


공통 필드를 매개변수로 받는 BaseResponse 객체 생성

open class BaseResponse(
    val resultCode: String = "",
    val resultMessage: String = ""
)

 

위 클래스는 특정 API의 Response data class가 상속 받을 클래스다.

 

BaseResponse 클래스를 상속 받는 LoginResponse (유저 로그인 API 응답 객체)

data class LoginResponse(
    val userId: String,
    // val resultCode: String,
    // val resultMessage: String
) : BaseResponse()

 

BaseResponse 클래스를 상속 받는 UserInfoResponse (유저 정보 조회 API 응답 객체)

data class UserInfoResponse(
    val userId: String,
    val name: String,
    val phone: String,
    val email: String,
    // val resultCode: String,
    // val resultMessage: String
) : BaseResponse()

 

LoginResponse, UserInfoResponse 모두 BaseResponse 클래스를 상속받음으로써 resultCode, resultMessage 필드를 작성하지 않아도 된다.

초기 값은 "" 빈 스트링으로 들어가며, 맨 위에서 예시를 든 json 응답 데이터를 받으면 다른 필드와 동일하게 resultCode, resultMessage에도 값이 들어간다.

 

만약 앱에서 처리하기 위해 공통 필드 값이 필요하다면 서버 개발자에게 해당 필드를 요청하고

앱에서는 BaseResponse 클래스에 한 줄만(예: val success: Bool) 추가해주면 값 하나가 BaseResponse를 상속 받는 모든 곳에 적용된다.

 

이처럼 코드의 유지보수성, 가독성, 확장성을 고려한 클래스 설계를 통해 효율적인 개발을 이루어 보도록 하자! 😁

 


💬 공통 필드는 항상 저 방식을 사용..? 🙅

앞에서 설명한 클래스 설계 방식이 무조건 위 방식을 사용할 수 있는 것은 아니다.

왜냐하면 나도 API 호출 후 내려오는 응답 값의 형식이 위에 작성한 json과 같은 형식이라서 위 구조를 설계했을 뿐...

공통 필드를 위한 효율적인 클래스 설계 방식은 여러가지가 있다.

 

예시를 하나 들자면 아래와 같은 json 형식이 있다.

{
  "resultCode": "0000",
  "resultMessage": "사용자 정보 조회 성공",
  "data": {
    "userId": "B0001",
    "name": "김블루",
    "phone": "010-1234-5678",
    "email": "blueland@blueland.com"
  }
}

위 코드는 resultCode, resultMessage, data(key) 까지가 공통 필드다. data(value) 쪽은 API 마다 다 다른 응답 객체가 들어가야한다.

사실 난 이 형태가 좀 더 예쁘다고 생각이 들어서, 서버 개발자와 함께 개발을 한다면 위 형식으로 내려달라고 요청할 것이다.

 

강조하자면 이 포스트는 위에 적은 방법만으로 사용하라고 적은 것이 아니다.

공통 필드를 효율적으로 다룰 수 있으며, 공통 필드가 있다면 이를 위한 클래스 설계를 할 수 있다는 것을 전달하기 위한 글이다.하고 싶었기 그러니 바로 위 형식에 대한 공통 필드를 다루는 코드는 작성하지 않겠다.

혹시 이 포스트를 보게될 개발자가 여러 형태의 데이터를 다루기 위해 고민하며, 효율적인 처리 방법을 터득했으면 좋겠다!


💬 글을 적다가 든 잡생각(?)

효율적인 고민을 하며 작성한 코드는 실력자가 이미 적용하고 있을 확률이 크다.

프로그램을 개발한 시간이 지나면서, 이전 또는 직전에 작성한 코드가 마음에 들지 않는다면 난 긍정적으로 본다 🤔

1. 시간이 없어서 난잡한 코드를 작성했거나 (시간 부족으로 인해 코드 품질이 낮아짐을 인식하고 있음)

2. 개발적으로 성장하여 마음에 들지 않는 것 (코드의 한계나 개선 가능성을 인식하고 있음)

 

아마 개발에 흥미없이 개발하는 사람이라면 이런저럭 생각이 안들지 않을까...