본문 바로가기
▶개발/Android

Android 공공 Open API를 retrofit2를 활용해서 사용하기.

by 브라더 준 2022. 4. 10.

공공 데이터 포털은 공공기관이 관리하는 공공데이터를 제공하는 창구이다. Oepn API 말고도 파일데이터나 시각화 자료까지도 접근, 이용할 수 있다. 뿐만 아니라 내가 원하는 데이터가 현재 제공되지 않는다면 별도로 제공 신청 프로세스도 밟을 수 있다고 한다.

이 글에서는 청약 관련 조회 API를 신청해서 가볍게 화면에 뿌려주는 것까지 진행해보려 한다.


Step 1. 아래 공공 데이터 포털 사이트에 접속/회원 가입 후, 메인화면 검색창에서 내가 사용하고자 하는 API 서비스를 검색하면 된다.

공공 데이터 포털 사이트 : https://www.data.go.kr/index.do

 

공공 데이터 포털 메인 검색창에 내가 사용하고 싶은 api 서비스를 검색하면 된다.




Step 2. 사용하고자 하는 Open API 활용 신청하기. 사용하고자 하는 API는 승인절차가 "자동승인", 혹은 "일반승인"으로 나눠지는 것 같다. 여기서 내가 신청한 API는 "자동승인"이라 간단한 신청 절차서 작성 후 바로 활용이 가능했다.

사용하고자 하는 Open API의 활용 신청 버튼을 누른다.
활용 신청 버튼을 누르면 활용목적에 대해서 간단하게 기재 후, 신청 과정을 밟는다.





Step3. 마이페이지 > 활용 > 내가 신청한 서비스를 확인할 수 있다. 해당 서비스 진입 후, api 문서와 함께 인증키를 확인할 수 있다. 해당 api 요청 시 인증키를 사용하여야 하고, 응답 시에는 api 문서를 참고해서 데이터 클래스를 만들어야 하므로 잘 저장해두자.

마이 페이지 > 신청한 서비스(개발계정 상세보기 화면)

 

api 문서를 제공하지 않고, 아래와 같이 요청 상세기능정보를 별도 표기하는 api도 있다. 이 경우에는 API목록에서 사용할 api를 확인하고, Models를 참고해서 응답 데이터 클래스 내부 변수들의 타입을 설정하면 된다.




Step4. retrofit2를 사용하기 위해 안드로이드 프로젝트에서 기본 설정을 진행한다.

retrofit은 안드로이드에서REST api 통신을 지원하기 위한 라이브러리다. 기존의 사용자가 http 통신을 위해 HttpURLConnection을 성립시키고 결과를 받아오는 과정이 다소 복잡하다. 여기에 더해서 AsyncTask가 deprecate되면서 서버와의 비동기 통신을 위해 골머리를 앓게 되는데.. retrofit은 Call 인터페이스의 enqueue을 통해 비동기 구현이 가능하다.(call 인터페이스의 enqueue를 이용하지 않고 rxjava, rxkotlin를 사용하여 비동기 처리할 수도 있다.)

*retrofit guide : https://square.github.io/retrofit/
[Call 인터페이스의 enqueue]
/**
 * Asynchronously send the request and notify {@code callback} of its response or if an error
 * occurred talking to the server, creating the request, or processing the response.
 */
void enqueue(Callback<T> callback);



- 권한, 의존성 설정
retrofit을 사용하기 앞서서 Manifest 권한 설정과 retrofit2를 사용하기 위해 gradle에 의존성을 추가해야 한다. 그래들 최신 버전은 retrofit github https://github.com/square/retrofit 링크를 통해 확인할 수 있다.

[AndroidManifest.xml]
    <!-- Http 통신을 하기 위해 인터넷 권한 허용 -->
    <uses-permission android:name="android.permission.INTERNET" />

 

 

[Module단 gradle]
    // json <-> 객체 변환하기 위해 사용
    implementation 'com.google.code.gson:gson:2.8.7'

    /**
     * retrofit 네트워크 라이브러리 관련
     */
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'



Step5. RetrofitClient 생성하기
위에서 저장해두었던 endPoint 주소가 BASE_URL로 두었음을 볼 수 있다. (endPoint 주소 뒤에 "/"를 꼭 추가한다.)

object RetrofitClient {
    /* Open API End Point Url */
    private const val BASE_URL = "https://api.odcloud.kr/api/ApplyhomeInfoDetailSvc/v1/"
    private var instance: Retrofit? = null

    open fun getInstance() : Retrofit {
        if (instance == null) {
            instance = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        } // end if

        return instance!!
    }

}



Step6.응답 DTO 만들기
공공 api에서 사용하고자 하는 서비스의 응답 model을 참고해서 resoponse Class를 만든다. 응답 데이터가 너무 방대하니, 일단 이 글에서는 주택관리번호, 주택명, 공급위치 3개의 데이터만을 가져오는 것으로 하겠다.

[공공 데이터 포털 api 문서]
getAPTLttotPblancDetail_model{
    HOUSE_MANAGE_NO	integer
    주택관리번호

    PBLANC_NO	integer
    공고번호

    HOUSE_NM	string
    주택명

    HSSPLY_ADRES	string
    공급위치

    TOT_SUPLY_HSHLDCO	integer
    공급규모

    RCRIT_PBLANC_DE	string
    모집공고일 (YYYY-MM-DD)

   ... (생략)
}


위의 api 문서를 참고하여 아래와 같이 DTO를 구현했다. 유의깊게 보아야 할 부분은 리스트부가 되는 부분은 별도로 data class를 만든 부분과 Gson 라이브러리의 @SerializedName 애노테이션이다. api 통신을 통해 받은 응답 json이 우리가 원하는 객체로 변환될 때, @SerializedName에 설정한 값을 가진 JSON 컬럼이 애노테이션이 선언된 변수로 반영된다. (아래에서는 응답 json의 HOUSE_MANAGE_NO -> houseManageNo로)

[aptLttotPblancDetailDTO.kt]
data class AptLttotPblancDetailResponse(
    @SerializedName("page")
    val page: Int,
    @SerializedName("perPage")
    val perPage: Int,
    @SerializedName("matchCount")
    val matchCount: Int,
    @SerializedName("totalCount")
    val totalCount: Int,
    @SerializedName("currentCount")
    val currentCount: Int,
    @SerializedName("data")
    val data: MutableList<AptItem>
)

data class AptItem(
    @SerializedName("HOUSE_MANAGE_NO")
    val houseManageNo: Int,
    @SerializedName("HOUSE_NM")
    val houseNm: String?,
    @SerializedName("HSSPLY_ADRES")
    val houseAddr: String?
)



Step7.API Interface 만들기.
응답 데이터 클래스가 완성됐으니, 실제로 api를 요청파트를 만들어야 한다. 이때에도 api 문서나 사용하는 공공 api 목록에서 요청 컬럼이나 형식을 참고해서 작성한다. (page, perPage 이외에도 다양한 요청 컬럼이 있지만 선택사항이므로 빠른 구현을 위해 생략한다.)

요청 예시

[CyApiService.kt]
/**
 * 청약 API
 */
interface CyApiService {

    companion object {
        private const val authKey = "부여받은 서비스키"
    }

    // 주택관리번호, 공고번호, 공고지역코드, 모집공고일 값을 이용하여 APT 분양정보의 상세정보를 제공
    @GET("getAPTLttotPblancDetail")
    fun getAPTLttotPblancDetail(
        @Query("page")
        page: Int = 1,
        @Query("perPage")
        perPage: Int = 10,
        @Query("serviceKey")
        serviceKey: String = authKey
    ) : Call<AptLttotPblancDetailDTO>

}



Step8.api 통신 / 뷰 데이터 셋팅

[MainActivity.kt]
 private fun requestAptCyList() {
        val cyListService = RetrofitClient.getInstance().create(CyApiService::class.java)
        val listCall = cyListService.getAPTLttotPblancDetail()
        listCall.enqueue(object : Callback<AptLttotPblancDetailDTO> {
            override fun onResponse(
                call: Call<AptLttotPblancDetailDTO>,
                response: Response<AptLttotPblancDetailDTO>
            ) {
                if (response.isSuccessful && response.code() == 200) {
                    cyListAdapter?.let {
                        it.setAptListItem(response.body()?.data ?: mutableListOf())
                    }

                } // end if
            }

            override fun onFailure(call: Call<AptLttotPblancDetailDTO>, t: Throwable) {
                // 실패
                Log.e("main_error", t.stackTrace.toString());

            }

        })
    }

api 결과를 성공적으로 리스트에 반영했다.


작업 소스 : https://github.com/markim94/Blog/tree/main/OpenApiProject 

 

+ 또한 해당 프로젝트에서 액티비티의 종속성 소거를 위해 binding adapter를 적용한 포스팅도 작성해두었습니다. (https://markim94.tistory.com/163)

반응형