๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Kotlin

[Android/Kotlin] ๋„ค์ด๋ฒ„ ์ง€๋„ API ๊ฒ€์ƒ‰

by naahy 2024. 2. 6.

๐Ÿ“Œ ์ง€๋„ ๊ฒ€์ƒ‰ ๊ด€๋ จ ๋ฌธ์„œ: https://developers.naver.com/docs/serviceapi/search/local/local.md

 

โ—์ฃผ์˜
๋„ค์ด๋ฒ„ ์ง€๋„ api๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด ๋„ค์ด๋ฒ„ ์ง€๋„ api๋งŒ ์‹ ์ฒญํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋”ฐ๋กœ ๊ฒ€์ƒ‰ api๋„ ์‹ ์ฒญํ•ด์•ผ ํ•œ๋‹ค.
์ฒ˜์Œ์— ์ด๊ฑธ ๋ชจ๋ฅด๊ณ  ๊ตฌํ˜„ํ•˜๋‹ค๊ฐ€ ํ•œ์ฐธ์„ ํ—ค๋งธ์Œ;

 

API ์‹ ์ฒญ

1. Naver Developers์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋“ฑ๋ก

https://developers.naver.com/apps/#/register

 

2. ์‚ฌ์šฉ API์—์„œ ๊ฒ€์ƒ‰ API ์„ ํƒ

 

3. ๋“ฑ๋ก

 

์ฝ”ํ‹€๋ฆฐ ํŒŒ์ผ ์ž‘์„ฑ

1. data class

์ •๋ณด ์ €์žฅ ์œ„ํ•œ ํด๋ž˜์Šค

data class Place(
    @SerializedName("title") val title: String,
    @SerializedName("description") val description: String,
    @SerializedName("address") val address: String,
    @SerializedName("roadAddress") val roadAddress: String
)

 

2. DTO

JSON์œผ๋กœ api ์š”์ฒญ ์‹œ ๋ฐ˜ํ™˜ ๋ฐ›์•˜์„ ๋•Œ items์— ๋‹ด๊ฒจ์žˆ๋Š” ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•จ

data class PlaceListDTO (
    @SerializedName("items") val places: List<Place>
)

 

3. ์ธํ„ฐํŽ˜์ด์Šค

๋งจ์ฒ˜์Œ ๋งํฌ ์ฒจ๋ถ€ํ•œ ๋ฌธ์„œ ์ฐธ๊ณ ํ•ด์„œ ๋ณธ์ธ์ด ํ•„์š”ํ•œ ๋‚ด์šฉ ์ž‘์„ฑํ•˜๋ฉด ๋จ

JSON์œผ๋กœ ๋ฐ˜ํ™˜๋ฐ›๋Š” url ์‚ฌ์šฉํ–ˆ์Œ

ํด๋ผ์ด์–ธํŠธ ์•„์ด๋””์™€ ์‹œํฌ๋ฆฟ์€ ๊ฒ€์ƒ‰ API ์‹ ์ฒญํ•˜๋ฉด ๋‚˜์˜ค๋Š” ๊ฑฐ ์‚ฌ์šฉ, Header ๊ฐ’์œผ๋กœ ๋„˜๊ฒจ์ค€๋‹ค

โ—Response๋กœ ๋ฐ›์•„์˜ฌ ๋• suspend ํ•จ์ˆ˜ ์‚ฌ์šฉ
interface NaverMapService {

    // ๋„ค์ด๋ฒ„ ์ง€๋„ ์žฅ์†Œ ๊ฒ€์ƒ‰ api
    @GET("/v1/search/local.json")
    suspend fun getMapSearch(
        @Query("query") query: String,      // ๊ฒ€์ƒ‰์–ด
        @Query("display") display: Int = 5,    // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ถœ๋ ฅ ๊ฑด์ˆ˜
        @Header("X-Naver-Client-Id") clientId: String = "๋‚ด ํด๋ผ์ด์–ธํŠธ ์•„์ด๋””",    // ๊ฒ€์ƒ‰ ํด๋ผ์ด์–ธํŠธ ์•„์ด๋””
        @Header("X-Naver-Client-Secret") clientSecret: String = "๋‚ด ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ",     // ๊ฒ€์ƒ‰ ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ
    ): Response<PlaceListDTO>

}

 

4. retrofit2 ์„ค์ •

private val gson = GsonBuilder().setLenient().create()
private val retrofit: Retrofit = Retrofit.Builder()
    .baseUrl("https://openapi.naver.com")
    .addConverterFactory(ScalarsConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

val mapService = retrofit.create(NaverMapService::class.java)

 

5. Activity ์ฝ”๋“œ

โ—suspend ํ•จ์ˆ˜ ์‚ฌ์šฉ ์‹œ lifecycleScope ์‚ฌ์šฉ
class PlaceSearchActivity : AppCompatActivity() {

	// 4. retrofit2 ์„ค์ • ๋ถ€๋ถ„
    private val binding by lazy { ActivityPlaceSearchBinding.inflate(layoutInflater) }
    private val gson = GsonBuilder().setLenient().create()
    private val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl("https://openapi.naver.com")
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()

    val mapService = retrofit.create(NaverMapService::class.java)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding.recyclerviewSearchPlace.layoutManager = LinearLayoutManager(this)
        setSearchView()	// ๊ฒ€์ƒ‰์–ด ์ž…๋ ฅํ•˜๋Š” ๋ถ€๋ถ„ ์„ค์ •

        setContentView(binding.root)
    }

    private fun setSearchView() {
    	// ๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ ๋ถ€๋ถ„
        binding.searchViewPlace.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String?): Boolean {
                lifecycleScope.launch {
                	// ๊ฐ’ ๋ฐ›์•„์˜ค๊ธฐ
                    val mapSearchList = mapService.getMapSearch(query!!)
                    binding.recyclerviewSearchPlace.adapter = PlaceSearchAdapter(mapSearchList.body()!!.places)
                    binding.recyclerviewSearchPlace.isVisible = true
                }
                return false
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                return false
            }
        })
    }

}

๋Œ“๊ธ€