23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
Tmap OpenAPI 와 텔레그램 봇을 활용한 주변 맛집 검색 기능 구현에 대해서 공부및 정리후 나만의 노하우와 지식을 공유한다.
1. Tmap OpenAPI 에 대해서 알아본다.
2. Tmap OpenAPI 와 텔레그램 봇을 활용한 주변 맛집 검색 기능을 간단하게 구현해 본다.
요즘에 제가 Tmap OpenAPI 에 대한 관심이 생겨서 해당 OpenAPI를 공부해서 어떤 기능을 개인적으로 구현해 볼까? (고민하던 중 ....)
역시나 관심있게 보던 텔레그램 봇을 활용해서 내가 검색하고자 하는 위치의 맛집과 음식점들을 텔레그램 봇 메시지로 전송해보면 어떨까?
해서 바로 Tmap OpenAPI를 공부한 지식을 토대로 기능을 구현해봤는데 그부분을 데보션에 정리해볼까합니다.
해당 블로그를 보시려면 사전지식으로 Tmap OpenAPI 에 대해서 공부를 하기위해서 우선 SK openAPI 사이트에 접속합니다.

아래와 같이 SK open api 는 TMAP 관련해서 OpenAPI 를 지원하고 있습니다.

TMAP API 버튼을 클릭해서 들어가보면 아래와 같은데요.
TMAP 은 여러가지를 지원하는 것으로 보이고요.
저는 제가 기능 구현에 활용할 TMAP Openapi 가 존재하는지 확인합니다.

정성스럽게 찾아보던 중 아래 Openapi를 발견합니다. (와! 내가 찾던 TMAP OpenAPI 구나!)

그리고, 좀 더 정성스럽게 자세히 읽어보니, 제가 찾던 TMAP Openapi 를 지원하고 있었습니다. (감사하게도요..!)
https://openapi.sk.com/products/detail?svcSeq=4&menuSeq=12
그리고, 해당페이지에서는 TMAP Openapi 를 잘 활용하라고 정성스럽게 쓰인 아래와 같이 예시도 있으니 참고합니다.

그리고 친절하게도 다양한 언어로 구현할 수 있도록 예시코드도 제공하고 실행도 가능합니다.
(저는 이게 가장 좋은것 같아요 ㅎㅎ 다양한 언어를 한번에 만나볼 수 있으니깐요.)
저는 이번 블로그에서 설명하고 개인적으로 개발할 언어인 Golang 를 선택해봅니다.

아래는 바로 GoLang 예시코드입니다.
package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://apis.openapi.sk.com/tmap/pois?version=1&searchKeyword=SK%20T%ED%83%80%EC%9B%8C&searchType=all&searchtypCd=A&reqCoordType=WGS84GEO&resCoordType=WGS84GEO&page=1&count=20&multiPoint=N&poiGroupYn=N"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Accept", "application/json")
req.Header.Add("appKey", 자신의 Appkey)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}실행해보니 아래와 같이 결과가 나오네요.
{
"searchPoiInfo": {
"totalCount": "41",
"count": "20",
"page": "1",
"pois": {
"poi": [
{
"id": "1128603",
"pkey": "112860300",
"navSeq": "0",
"collectionType": "poi",
"name": "SKT타워",
"telNo": "",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"noorLat": "37.56648210",
"noorLon": "126.98510375",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "건물/시설",
"middleBizName": "주요건물",
"lowerBizName": "주요빌딩",
"detailBizName": "30층이상",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56648210",
"centerLon": "126.98510375",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "1128603",
"pkey": "112860303",
"navSeq": "3",
"collectionType": "poi",
"name": "SKT타워 정문",
"telNo": "",
"frontLat": "37.56620435",
"frontLon": "126.98474268",
"noorLat": "37.56620435",
"noorLon": "126.98474268",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "건물/시설",
"middleBizName": "주요건물",
"lowerBizName": "주요빌딩",
"detailBizName": "30층이상",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56620435",
"centerLon": "126.98474268",
"frontLat": "37.56620435",
"frontLon": "126.98474268",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "1128603",
"pkey": "112860304",
"navSeq": "4",
"collectionType": "poi",
"name": "SKT타워 후문",
"telNo": "",
"frontLat": "37.56670430",
"frontLon": "126.98521485",
"noorLat": "37.56670430",
"noorLon": "126.98521485",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "건물/시설",
"middleBizName": "주요건물",
"lowerBizName": "주요빌딩",
"detailBizName": "30층이상",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56670430",
"centerLon": "126.98521485",
"frontLat": "37.56670430",
"frontLon": "126.98521485",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10202403",
"pkey": "1020240302",
"navSeq": "2",
"collectionType": "poi",
"name": "SKT타워 주차장",
"telNo": "",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"noorLat": "37.56650987",
"noorLon": "126.98507598",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "교통편의",
"middleBizName": "자동차시설",
"lowerBizName": "주차장",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56650987",
"centerLon": "126.98507598",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "0",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10140126",
"pkey": "1014012601",
"navSeq": "1",
"collectionType": "poi",
"name": "SK텔레콤T타워B4 전기차충전소",
"telNo": "",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"noorLat": "37.56642655",
"noorLon": "126.98504821",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "교통편의",
"middleBizName": "자동차시설",
"lowerBizName": "전기차충전소",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "6",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56642655",
"centerLon": "126.98504821",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "0",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": [
{
"operatorId": "EV",
"stationId": "EV003215",
"chargerId": "03",
"status": "2",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730153610",
"updateDateTime": "20240730203749",
"isFast": "N",
"isAvailable": "Y"
},
{
"operatorId": "EV",
"stationId": "EV003215",
"chargerId": "01",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240729114026",
"updateDateTime": "20240730080132",
"isFast": "N",
"isAvailable": "N"
},
{
"operatorId": "EV",
"stationId": "EV003215",
"chargerId": "02",
"status": "2",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730171917",
"updateDateTime": "20240730172953",
"isFast": "N",
"isAvailable": "Y"
},
{
"operatorId": "EV",
"stationId": "EV003215",
"chargerId": "04",
"status": "2",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730103936",
"updateDateTime": "20240730191947",
"isFast": "N",
"isAvailable": "Y"
}
]
}
},
{
"id": "10140136",
"pkey": "1014013601",
"navSeq": "1",
"collectionType": "poi",
"name": "SK텔레콤T타워B3 전기차충전소",
"telNo": "",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"noorLat": "37.56648210",
"noorLon": "126.98504820",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "교통편의",
"middleBizName": "자동차시설",
"lowerBizName": "전기차충전소",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "6",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56648210",
"centerLon": "126.98504820",
"frontLat": "37.56656541",
"frontLon": "126.98452047",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "0",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": [
{
"operatorId": "EV",
"stationId": "EV003214",
"chargerId": "04",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730092203",
"updateDateTime": "20240730093643",
"isFast": "N",
"isAvailable": "N"
},
{
"operatorId": "EV",
"stationId": "EV003214",
"chargerId": "02",
"status": "2",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730141739",
"updateDateTime": "20240730181002",
"isFast": "N",
"isAvailable": "Y"
},
{
"operatorId": "EV",
"stationId": "EV003214",
"chargerId": "01",
"status": "2",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730145834",
"updateDateTime": "20240730190310",
"isFast": "N",
"isAvailable": "Y"
},
{
"operatorId": "EV",
"stationId": "EV003214",
"chargerId": "03",
"status": "1",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240729133209",
"updateDateTime": "20240730090627",
"isFast": "N",
"isAvailable": "N"
}
]
}
},
{
"id": "10140131",
"pkey": "1014013101",
"navSeq": "1",
"collectionType": "poi",
"name": "SK텔레콤T타워B5 전기차충전소",
"telNo": "",
"frontLat": "37.56656541",
"frontLon": "126.98454825",
"noorLat": "37.56648210",
"noorLon": "126.98504820",
"upperAddrName": "서울",
"middleAddrName": "중구",
"lowerAddrName": "을지로2가",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "11",
"secondNo": "0",
"roadName": "을지로",
"firstBuildNo": "65",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "교통편의",
"middleBizName": "자동차시설",
"lowerBizName": "전기차충전소",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "6",
"zipCode": "04539",
"adminDongCode": "1114055000",
"legalDongCode": "1114010500",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.56648210",
"centerLon": "126.98504820",
"frontLat": "37.56656541",
"frontLon": "126.98454825",
"roadName": "을지로",
"bldNo1": "65",
"bldNo2": "0",
"roadId": "00255",
"fullAddressRoad": "서울 중구 을지로 65"
}
]
},
"evChargers": {
"evCharger": [
{
"operatorId": "EV",
"stationId": "EV003216",
"chargerId": "03",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240724212545",
"updateDateTime": "20240730182942",
"isFast": "N",
"isAvailable": "N"
},
{
"operatorId": "EV",
"stationId": "EV003216",
"chargerId": "05",
"status": "2",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240730082752",
"updateDateTime": "20240730190025",
"isFast": "N",
"isAvailable": "Y"
},
{
"operatorId": "EV",
"stationId": "EV003216",
"chargerId": "04",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240723230014",
"updateDateTime": "20240724120702",
"isFast": "N",
"isAvailable": "N"
},
{
"operatorId": "EV",
"stationId": "EV003216",
"chargerId": "01",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240723231805",
"updateDateTime": "20240724120702",
"isFast": "N",
"isAvailable": "N"
},
{
"operatorId": "EV",
"stationId": "EV003216",
"chargerId": "02",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240724195416",
"updateDateTime": "20240729191037",
"isFast": "N",
"isAvailable": "N"
},
{
"operatorId": "EV",
"stationId": "EV003216",
"chargerId": "06",
"status": "3",
"type": "02",
"powerType": "완속(7kW단독)",
"operatorName": "에버온",
"chargingDateTime": "20240729171154",
"updateDateTime": "20240730075749",
"isFast": "N",
"isAvailable": "N"
}
]
}
},
{
"id": "1130908",
"pkey": "113090800",
"navSeq": "0",
"collectionType": "poi",
"name": "SK M CITY",
"telNo": "031-931-9001",
"frontLat": "37.65385701",
"frontLon": "126.77175964",
"noorLat": "37.65438471",
"noorLon": "126.77070417",
"upperAddrName": "경기",
"middleAddrName": "고양시 일산동구",
"lowerAddrName": "장항동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "869",
"secondNo": "0",
"roadName": "백마로",
"firstBuildNo": "195",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "건물/시설",
"middleBizName": "주요건물",
"lowerBizName": "주상복합",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "10403",
"adminDongCode": "4128559000",
"legalDongCode": "4128510400",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.65438471",
"centerLon": "126.77070417",
"frontLat": "37.65385701",
"frontLon": "126.77175964",
"roadName": "백마로",
"bldNo1": "195",
"bldNo2": "",
"roadId": "00109",
"fullAddressRoad": "경기 고양시 일산동구 백마로 195"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "1130908",
"pkey": "113090801",
"navSeq": "1",
"collectionType": "poi",
"name": "SK M CITY 정문",
"telNo": "031-931-9001",
"frontLat": "37.65385701",
"frontLon": "126.77175964",
"noorLat": "37.65385701",
"noorLon": "126.77175964",
"upperAddrName": "경기",
"middleAddrName": "고양시 일산동구",
"lowerAddrName": "장항동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "869",
"secondNo": "0",
"roadName": "백마로",
"firstBuildNo": "195",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "건물/시설",
"middleBizName": "주요건물",
"lowerBizName": "주상복합",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "10403",
"adminDongCode": "4128559000",
"legalDongCode": "4128510400",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.65385701",
"centerLon": "126.77175964",
"frontLat": "37.65385701",
"frontLon": "126.77175964",
"roadName": "백마로",
"bldNo1": "195",
"bldNo2": "",
"roadId": "00109",
"fullAddressRoad": "경기 고양시 일산동구 백마로 195"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "1130908",
"pkey": "113090802",
"navSeq": "2",
"collectionType": "poi",
"name": "SK M CITY 후문",
"telNo": "031-931-9001",
"frontLat": "37.65474576",
"frontLon": "126.77017643",
"noorLat": "37.65474576",
"noorLon": "126.77017643",
"upperAddrName": "경기",
"middleAddrName": "고양시 일산동구",
"lowerAddrName": "장항동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "869",
"secondNo": "0",
"roadName": "백마로",
"firstBuildNo": "195",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "건물/시설",
"middleBizName": "주요건물",
"lowerBizName": "주상복합",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "10403",
"adminDongCode": "4128559000",
"legalDongCode": "4128510400",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.65474576",
"centerLon": "126.77017643",
"frontLat": "37.65474576",
"frontLon": "126.77017643",
"roadName": "백마로",
"bldNo1": "195",
"bldNo2": "",
"roadId": "00109",
"fullAddressRoad": "경기 고양시 일산동구 백마로 195"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "8086964",
"pkey": "808696401",
"navSeq": "1",
"collectionType": "poi",
"name": "커피빈 여의도K타워점",
"telNo": "02-3468-1600",
"frontLat": "37.51976429",
"frontLon": "126.92844357",
"noorLat": "37.51973651",
"noorLon": "126.92805472",
"upperAddrName": "서울",
"middleAddrName": "영등포구",
"lowerAddrName": "여의도동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "45",
"secondNo": "1",
"roadName": "국제금융로8길",
"firstBuildNo": "31",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "생활편의",
"middleBizName": "카페",
"lowerBizName": "커피전문점",
"detailBizName": "커피빈",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "07332",
"adminDongCode": "1156054000",
"legalDongCode": "1156011000",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.51973651",
"centerLon": "126.92805472",
"frontLat": "37.51976429",
"frontLon": "126.92844357",
"roadName": "국제금융로8길",
"bldNo1": "31",
"bldNo2": "0",
"roadId": "00070",
"fullAddressRoad": "서울 영등포구 국제금융로8길 31"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "8086964",
"pkey": "808696403",
"navSeq": "3",
"collectionType": "poi",
"name": "커피빈 여의도K타워점 주차장",
"telNo": "02-3468-1600",
"frontLat": "37.51976429",
"frontLon": "126.92844357",
"noorLat": "37.51976429",
"noorLon": "126.92844357",
"upperAddrName": "서울",
"middleAddrName": "영등포구",
"lowerAddrName": "여의도동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "45",
"secondNo": "1",
"roadName": "국제금융로8길",
"firstBuildNo": "31",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "생활편의",
"middleBizName": "카페",
"lowerBizName": "커피전문점",
"detailBizName": "커피빈",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "07332",
"adminDongCode": "1156054000",
"legalDongCode": "1156011000",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.51976429",
"centerLon": "126.92844357",
"frontLat": "37.51976429",
"frontLon": "126.92844357",
"roadName": "국제금융로8길",
"bldNo1": "31",
"bldNo2": "0",
"roadId": "00070",
"fullAddressRoad": "서울 영등포구 국제금융로8길 31"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10165080",
"pkey": "1016508001",
"navSeq": "1",
"collectionType": "poi",
"name": "SK텔레콤 HK대리점 동탄영천직영점",
"telNo": "070-4617-0400",
"frontLat": "37.20733133",
"frontLon": "127.09849245",
"noorLat": "37.20719246",
"noorLon": "127.09840912",
"upperAddrName": "경기",
"middleAddrName": "화성시",
"lowerAddrName": "영천동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "658",
"secondNo": "1",
"roadName": "동탄대로",
"firstBuildNo": "599",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "쇼핑",
"middleBizName": "정보통신기기",
"lowerBizName": "SK텔레콤",
"detailBizName": "SKT대리점",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "1",
"desc": "SK텔레콤 공식인증대리점 HK대리점 동탄영천직영점입니다.",
"dataKind": "",
"zipCode": "18471",
"adminDongCode": "4159059000",
"legalDongCode": "4159013100",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.20719246",
"centerLon": "127.09840912",
"frontLat": "37.20733133",
"frontLon": "127.09849245",
"roadName": "동탄대로",
"bldNo1": "599",
"bldNo2": "0",
"roadId": "01767",
"fullAddressRoad": "경기 화성시 동탄대로 599"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10019939",
"pkey": "1001993901",
"navSeq": "1",
"collectionType": "poi",
"name": "김도희의갈치창고",
"telNo": "064-712-1802",
"frontLat": "33.46707731",
"frontLon": "126.45717132",
"noorLat": "33.46710508",
"noorLon": "126.45675469",
"upperAddrName": "제주",
"middleAddrName": "제주시",
"lowerAddrName": "해안동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "2171",
"secondNo": "0",
"roadName": "노형로",
"firstBuildNo": "121",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "생활편의",
"middleBizName": "음식점",
"lowerBizName": "한식",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "1",
"desc": "애월에서는 이름만 걸고 영업했는데 이전하고는 얼굴까지 걸고 영업 개시했습니다. 오시는 손님마다 제주은갈치조림과 통갈치구이 등 갈치요리 찐맛집이라고 엄지척! 하는 대한민국 최고의 갈치전문식당을 지향하는 갈치맛집입니다. 엄청난 홍보비용으로 호객 행위를 하는 관광객을 1회성 소비자로 보는 몇몇 유명 관광식당들과는 달리 오시는 한 분 한 분 평생 고객으로 생각하고 만족한 식사를 하고 가실 수 있도록 최고의 맛을 낼 수 있도록 노력하고 있으며, 실제로 재방문율이 아주 높습니다. 2021년 9월 25일 이전 첫날, 네이버플레이스를 제외한 온라인-일반네비게이션 주소 변경이 되지 않은 상황에서도 수십 팀이 소개 받고, 재방문으로..전화로 물어 물어 찾아올 정도네요.\n애월 하귀에서 2019년 10월 14평 작은 규모로 오픈, 개업한지 얼마되지 않은 2020년 초 코로나사태가 발생했으나 개업 초기부터 맛집으로 입소문을 타 코로나 정국속에서도 많은 분들이 찾아주셔서 좁은 가게로는 더 이상 감당이 안 돼, 보다 쾌적하고 편안하게 식사하고 가실 수 있도록 개업 2년이 안 되어 100여평 넓은 가게를 얻어 확장 이전하게 되었습니다. \n재료 신선도 보장합니다. \n맛 보장합니다.\n갈치 퀄리티 대비 가성비 보장합니다.\n위생, 청결, 친절은 기본입니다.\n저희는 집밥 + 갈치전문식당의 컨셉으로 100% 직접 만든 집반찬 제공합니다. 가격상승요인인 곁반찬(일명 스끼다시)은 제공하지 않습니다. 문어/전복/새우 등 갈치 본연의 맛을 지워버리는 각종 해산물 넣고 통갈치조림으로 비주얼 장사하는 유명 식당들에 현혹되지 마시고 갈치 자체의 맛을 극대화시킨 저희 조림/통갈치구이 드시러 오세요. 밤새 잡은 우주 최고 신선도의 당일바리갈치 도매가로 전국택배 판매하니 참조하세요.\n코로나 때문에 고가의 바이러스 클린존을 설치하고, 홀에 식탁을 다 채우지 않고 넓게 배치하였으니 안심하고 방문하십시오.\n각종 광고 대행 연락 사절! 각종 포스팅, 리뷰(후기) 유인 인센티브 운영하지 않습니다. 감사합니다.",
"dataKind": "",
"zipCode": "63076",
"adminDongCode": "5011025300",
"legalDongCode": "5011013900",
"newAddressList": {
"newAddress": [
{
"centerLat": "33.46710508",
"centerLon": "126.45675469",
"frontLat": "33.46707731",
"frontLon": "126.45717132",
"roadName": "노형로",
"bldNo1": "121",
"bldNo2": "0",
"roadId": "00452",
"fullAddressRoad": "제주 제주시 노형로 121"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10019939",
"pkey": "1001993902",
"navSeq": "2",
"collectionType": "poi",
"name": "김도희의갈치창고 주차장",
"telNo": "064-712-1802",
"frontLat": "33.46707731",
"frontLon": "126.45717132",
"noorLat": "33.46707731",
"noorLon": "126.45717132",
"upperAddrName": "제주",
"middleAddrName": "제주시",
"lowerAddrName": "해안동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "2171",
"secondNo": "0",
"roadName": "노형로",
"firstBuildNo": "121",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "생활편의",
"middleBizName": "음식점",
"lowerBizName": "한식",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "1",
"desc": "애월에서는 이름만 걸고 영업했는데 이전하고는 얼굴까지 걸고 영업 개시했습니다. 오시는 손님마다 제주은갈치조림과 통갈치구이 등 갈치요리 찐맛집이라고 엄지척! 하는 대한민국 최고의 갈치전문식당을 지향하는 갈치맛집입니다. 엄청난 홍보비용으로 호객 행위를 하는 관광객을 1회성 소비자로 보는 몇몇 유명 관광식당들과는 달리 오시는 한 분 한 분 평생 고객으로 생각하고 만족한 식사를 하고 가실 수 있도록 최고의 맛을 낼 수 있도록 노력하고 있으며, 실제로 재방문율이 아주 높습니다. 2021년 9월 25일 이전 첫날, 네이버플레이스를 제외한 온라인-일반네비게이션 주소 변경이 되지 않은 상황에서도 수십 팀이 소개 받고, 재방문으로..전화로 물어 물어 찾아올 정도네요.\n애월 하귀에서 2019년 10월 14평 작은 규모로 오픈, 개업한지 얼마되지 않은 2020년 초 코로나사태가 발생했으나 개업 초기부터 맛집으로 입소문을 타 코로나 정국속에서도 많은 분들이 찾아주셔서 좁은 가게로는 더 이상 감당이 안 돼, 보다 쾌적하고 편안하게 식사하고 가실 수 있도록 개업 2년이 안 되어 100여평 넓은 가게를 얻어 확장 이전하게 되었습니다. \n재료 신선도 보장합니다. \n맛 보장합니다.\n갈치 퀄리티 대비 가성비 보장합니다.\n위생, 청결, 친절은 기본입니다.\n저희는 집밥 + 갈치전문식당의 컨셉으로 100% 직접 만든 집반찬 제공합니다. 가격상승요인인 곁반찬(일명 스끼다시)은 제공하지 않습니다. 문어/전복/새우 등 갈치 본연의 맛을 지워버리는 각종 해산물 넣고 통갈치조림으로 비주얼 장사하는 유명 식당들에 현혹되지 마시고 갈치 자체의 맛을 극대화시킨 저희 조림/통갈치구이 드시러 오세요. 밤새 잡은 우주 최고 신선도의 당일바리갈치 도매가로 전국택배 판매하니 참조하세요.\n코로나 때문에 고가의 바이러스 클린존을 설치하고, 홀에 식탁을 다 채우지 않고 넓게 배치하였으니 안심하고 방문하십시오.\n각종 광고 대행 연락 사절! 각종 포스팅, 리뷰(후기) 유인 인센티브 운영하지 않습니다. 감사합니다.",
"dataKind": "",
"zipCode": "63076",
"adminDongCode": "5011025300",
"legalDongCode": "5011013900",
"newAddressList": {
"newAddress": [
{
"centerLat": "33.46707731",
"centerLon": "126.45717132",
"frontLat": "33.46707731",
"frontLon": "126.45717132",
"roadName": "노형로",
"bldNo1": "121",
"bldNo2": "0",
"roadId": "00452",
"fullAddressRoad": "제주 제주시 노형로 121"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "8534096",
"pkey": "853409601",
"navSeq": "1",
"collectionType": "poi",
"name": "에이미스커피 가산SK트윈타워점",
"telNo": "02-355-1911",
"frontLat": "37.47562971",
"frontLon": "126.88292118",
"noorLat": "37.47562971",
"noorLon": "126.88292118",
"upperAddrName": "서울",
"middleAddrName": "금천구",
"lowerAddrName": "가산동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "345",
"secondNo": "9",
"roadName": "가산디지털1로",
"firstBuildNo": "119",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "생활편의",
"middleBizName": "카페",
"lowerBizName": "카페기타",
"detailBizName": "기타",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "08589",
"adminDongCode": "1154551000",
"legalDongCode": "1154510100",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.47562971",
"centerLon": "126.88292118",
"frontLat": "37.47562971",
"frontLon": "126.88292118",
"roadName": "가산디지털1로",
"bldNo1": "119",
"bldNo2": "",
"roadId": "00002",
"fullAddressRoad": "서울 금천구 가산디지털1로 119"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10165066",
"pkey": "1016506601",
"navSeq": "1",
"collectionType": "poi",
"name": "SK텔레콤 PS&M 둔산본점",
"telNo": "070-7470-7641",
"frontLat": "36.35176825",
"frontLon": "127.38790662",
"noorLat": "36.35146273",
"noorLon": "127.38793441",
"upperAddrName": "대전",
"middleAddrName": "서구",
"lowerAddrName": "둔산동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "1455",
"secondNo": "0",
"roadName": "둔산로",
"firstBuildNo": "125",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "쇼핑",
"middleBizName": "정보통신기기",
"lowerBizName": "SK텔레콤",
"detailBizName": "SKT대리점",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "1",
"desc": "기계식 주차장으로 승용차만 가능합니다. 2시간 지원됩니다.",
"dataKind": "",
"zipCode": "35240",
"adminDongCode": "3017063000",
"legalDongCode": "3017011200",
"newAddressList": {
"newAddress": [
{
"centerLat": "36.35146273",
"centerLon": "127.38793441",
"frontLat": "36.35176825",
"frontLon": "127.38790662",
"roadName": "둔산로",
"bldNo1": "125",
"bldNo2": "0",
"roadId": "00342",
"fullAddressRoad": "대전 서구 둔산로 125"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "10165066",
"pkey": "1016506602",
"navSeq": "2",
"collectionType": "poi",
"name": "SK텔레콤 PS&M 둔산본점 주차장",
"telNo": "070-7470-7641",
"frontLat": "36.35176825",
"frontLon": "127.38790662",
"noorLat": "36.35176825",
"noorLon": "127.38790662",
"upperAddrName": "대전",
"middleAddrName": "서구",
"lowerAddrName": "둔산동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "1455",
"secondNo": "0",
"roadName": "둔산로",
"firstBuildNo": "125",
"secondBuildNo": "0",
"radius": "0.0",
"bizName": "",
"upperBizName": "쇼핑",
"middleBizName": "정보통신기기",
"lowerBizName": "SK텔레콤",
"detailBizName": "SKT대리점",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "1",
"desc": "기계식 주차장으로 승용차만 가능합니다. 2시간 지원됩니다.",
"dataKind": "",
"zipCode": "35240",
"adminDongCode": "3017063000",
"legalDongCode": "3017011200",
"newAddressList": {
"newAddress": [
{
"centerLat": "36.35176825",
"centerLon": "127.38790662",
"frontLat": "36.35176825",
"frontLon": "127.38790662",
"roadName": "둔산로",
"bldNo1": "125",
"bldNo2": "0",
"roadId": "00342",
"fullAddressRoad": "대전 서구 둔산로 125"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "7402574",
"pkey": "740257401",
"navSeq": "1",
"collectionType": "poi",
"name": "SK텔레콤 코넥대리점 위례광장직영점",
"telNo": "031-759-5530",
"frontLat": "37.47330144",
"frontLon": "127.14975808",
"noorLat": "37.47352364",
"noorLon": "127.15006360",
"upperAddrName": "경기",
"middleAddrName": "성남시 수정구",
"lowerAddrName": "창곡동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "513",
"secondNo": "0",
"roadName": "위례동로",
"firstBuildNo": "153",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "쇼핑",
"middleBizName": "정보통신기기",
"lowerBizName": "SK텔레콤",
"detailBizName": "SKT대리점",
"rpFlag": "16",
"parkFlag": "1",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "13642",
"adminDongCode": "4113162500",
"legalDongCode": "4113110800",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.47352364",
"centerLon": "127.15006360",
"frontLat": "37.47330144",
"frontLon": "127.14975808",
"roadName": "위례동로",
"bldNo1": "153",
"bldNo2": "",
"roadId": "00661",
"fullAddressRoad": "경기 성남시 수정구 위례동로 153"
}
]
},
"evChargers": {
"evCharger": []
}
},
{
"id": "7402574",
"pkey": "740257402",
"navSeq": "2",
"collectionType": "poi",
"name": "SK텔레콤 코넥대리점 위례광장직영점 주차장",
"telNo": "031-759-5530",
"frontLat": "37.47330144",
"frontLon": "127.14975808",
"noorLat": "37.47330144",
"noorLon": "127.14975808",
"upperAddrName": "경기",
"middleAddrName": "성남시 수정구",
"lowerAddrName": "창곡동",
"detailAddrName": "",
"mlClass": "1",
"firstNo": "513",
"secondNo": "0",
"roadName": "위례동로",
"firstBuildNo": "153",
"secondBuildNo": "",
"radius": "0.0",
"bizName": "",
"upperBizName": "쇼핑",
"middleBizName": "정보통신기기",
"lowerBizName": "SK텔레콤",
"detailBizName": "SKT대리점",
"rpFlag": "16",
"parkFlag": "0",
"detailInfoFlag": "0",
"desc": "",
"dataKind": "",
"zipCode": "13642",
"adminDongCode": "4113162500",
"legalDongCode": "4113110800",
"newAddressList": {
"newAddress": [
{
"centerLat": "37.47330144",
"centerLon": "127.14975808",
"frontLat": "37.47330144",
"frontLon": "127.14975808",
"roadName": "위례동로",
"bldNo1": "153",
"bldNo2": "",
"roadId": "00661",
"fullAddressRoad": "경기 성남시 수정구 위례동로 153"
}
]
},
"evChargers": {
"evCharger": []
}
}
]
}
}
}그리고 TMAP Openapi 파라미터 중 제가 필요한 파라미터 정보를 간단하게 정리해보자면요.
키워드로 검색을 위해서 사용하는 searchKeyword 파라미터가 존재하는데 가장 중요한 파라미터입니다.

그리고 아래 파라미터들도 중요하겠죠?
경도와 위도 등록

그리고 위치기반으로 검색 반경인 radius , 검색결과개수 count , 기본결과만 반환할지에 대한 mutipoint 등도 눈여겨 볼만합니다.

아무튼, 저는 Tmap OpenAPI를 공부해서 나름대로 테스트도 해보고 파라미터들도 눈여겨보면서 어떻게 제가 생각한 내용을 구현할지 머릿속에 정리해봅니다.
그리고 머리속에 정리한 내용을 토대로 제가 구현해야할 함수는 아래와 같이 2가지 정도를 구현하면 될것 같다는 생각이 듭니다.
하나, 기준이 될 위치의 경도와 위도를 가져올 함수를 작성합니다.
둘, 기준이 될 위치의 경도와 위도에서 2km 반경에 음식점을 조회하는 함수를 작성합니다.
아래와 같이 함수를 구현합니다.
1. 기준위치
특정 위치 keyword를 파라미터로 받고, POI 정보를 리턴하면 될것 같습니다.
// POI 데이터를 검색하는 함수 정의
func getPOIByKeyword(keyword string) (*POI, error) {
// URL 인코딩
encodedKeyword := url.QueryEscape(keyword)
// Tmap API URL 생성
url := fmt.Sprintf("https://apis.openapi.sk.com/tmap/pois?version=1&appKey=%s&searchKeyword=%s", TmapApiKey, encodedKeyword)
// HTTP GET 요청
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// JSON 응답 파싱
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
pois := result["searchPoiInfo"].(map[string]interface{})["pois"].(map[string]interface{})["poi"]
var retPOI *POI
for _, poi := range pois.([]interface{}) {
item := poi.(map[string]interface{})
Name := item["name"].(string)
noorLat := item["noorLat"].(string)
noorLon := item["noorLon"].(string)
fmt.Printf("검색키워드[%s] : POI 반환위치[%s] 위도[%s] 경도[%s]\n", keyword, Name, noorLat, noorLon)
retPOI = &POI{
Latitude: noorLat,
Longitude: noorLon,
Name: Name,
}
break
}
return retPOI, nil
}2. 기준위치 반경 2km 음식점
위 함수에서 구한 기준 위치의 위도과 경도를 파라미터로 받고 radius 를 2로 주며, multipoint 를 Y 로 주게 되면 드디어 원하던 주변 음식점 정보를 얻어올 수 있습니다.
func findRestaurants(centerLat string, centerLon string) ([]string, error) {
endpoint := "https://apis.openapi.sk.com/tmap/pois?version=1&format=json"
params := url.Values{}
params.Set("appKey", TmapApiKey)
params.Set("searchKeyword", "음식점")
params.Set("centerLat", centerLat)
params.Set("centerLon", centerLon)
params.Set("radius", "2") // 2km 반경
params.Set("count", "5")
params.Set("multiPoint", "Y")
reqURL := fmt.Sprintf("%s&%s", endpoint, params.Encode())
resp, err := http.Get(reqURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
pois := result["searchPoiInfo"].(map[string]interface{})["pois"].(map[string]interface{})["poi"]
var restaurantInfo []string
for _, poi := range pois.([]interface{}) {
item := poi.(map[string]interface{})
name := item["name"].(string)
radius, err := strconv.ParseFloat(item["radius"].(string), 64)
if err != nil {
log.Fatalf("Error converting string to float64: %v", err)
}
desc := "정보없음"
if value, ok := item["desc"].(string); ok && value != "" {
desc = strings.ReplaceAll(value, "%", "프로")
desc = strings.ReplaceAll(desc, "\n", " ") // 줄 바꿈을 공백으로 변경
}
radiusStr := formatRadius(radius)
lat := item["noorLat"].(string)
lon := item["noorLon"].(string)
googleMapURI := fmt.Sprintf(`<a href="https://www.google.com/maps?q=%s,%s" target="_blank">구글지도보기</a>`, lat, lon)
restaurantInfo = append(restaurantInfo, fmt.Sprintf("이름: %s\n주소: %s\n전화번호: %s\n특징: %s\n반경: %s\n%s\n",
name,
item["newAddressList"].(map[string]interface{})["newAddress"].([]interface{})[0].(map[string]interface{})["fullAddressRoad"].(string),
item["telNo"].(string),
desc,
radiusStr,
googleMapURI,
))
}
return restaurantInfo, nil
}아래는 gin 프레임워크를 활용한 전체 코드입니다.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/gin-gonic/gin"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
)
const telegramBotToken = "텔레그램봇 토큰정보"
const telegramChannelID = 텔레그램봇 채널ID
const TmapApiKey = "SK openapi Appkey"
// POI 정보를 담는 구조체 정의
type POI struct {
Latitude string `json:"noorLat"`
Longitude string `json:"noorLon"`
Name string `json:"name"`
}
// RequestData 구조체 정의
type RequestData struct {
Msg string `json:"msg"`
SenderName string `json:"sender_name"`
}
func formatRadius(radius float64) string {
if radius < 1 {
// radius가 1보다 작은 경우 미터 단위로 표시
meters := radius * 1000 // 미터 단위로 변환
return fmt.Sprintf("%.0fm", meters)
} else {
// radius가 1 이상인 경우 킬로미터 단위로 표시
return fmt.Sprintf("%.1fkm", radius)
}
}
// POI 데이터를 검색하는 함수 정의
func getPOIByKeyword(keyword string) (*POI, error) {
// URL 인코딩
encodedKeyword := url.QueryEscape(keyword)
// Tmap API URL 생성
url := fmt.Sprintf("https://apis.openapi.sk.com/tmap/pois?version=1&appKey=%s&searchKeyword=%s", TmapApiKey, encodedKeyword)
// HTTP GET 요청
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// JSON 응답 파싱
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
pois := result["searchPoiInfo"].(map[string]interface{})["pois"].(map[string]interface{})["poi"]
var retPOI *POI
for _, poi := range pois.([]interface{}) {
item := poi.(map[string]interface{})
Name := item["name"].(string)
noorLat := item["noorLat"].(string)
noorLon := item["noorLon"].(string)
fmt.Printf("검색키워드[%s] : POI 반환위치[%s] 위도[%s] 경도[%s]\n", keyword, Name, noorLat, noorLon)
retPOI = &POI{
Latitude: noorLat,
Longitude: noorLon,
Name: Name,
}
break
}
return retPOI, nil
}
func findRestaurants(centerLat string, centerLon string) ([]string, error) {
endpoint := "https://apis.openapi.sk.com/tmap/pois?version=1&format=json"
params := url.Values{}
params.Set("appKey", TmapApiKey)
params.Set("searchKeyword", "음식점")
params.Set("centerLat", centerLat)
params.Set("centerLon", centerLon)
params.Set("radius", "2") // 2km 반경
params.Set("count", "5")
params.Set("multiPoint", "Y")
reqURL := fmt.Sprintf("%s&%s", endpoint, params.Encode())
resp, err := http.Get(reqURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
pois := result["searchPoiInfo"].(map[string]interface{})["pois"].(map[string]interface{})["poi"]
var restaurantInfo []string
for _, poi := range pois.([]interface{}) {
item := poi.(map[string]interface{})
name := item["name"].(string)
radius, err := strconv.ParseFloat(item["radius"].(string), 64)
if err != nil {
log.Fatalf("Error converting string to float64: %v", err)
}
desc := "정보없음"
if value, ok := item["desc"].(string); ok && value != "" {
desc = strings.ReplaceAll(value, "%", "프로")
desc = strings.ReplaceAll(desc, "\n", " ") // 줄 바꿈을 공백으로 변경
}
radiusStr := formatRadius(radius)
lat := item["noorLat"].(string)
lon := item["noorLon"].(string)
googleMapURI := fmt.Sprintf(`<a href="https://www.google.com/maps?q=%s,%s" target="_blank">구글지도보기</a>`, lat, lon)
restaurantInfo = append(restaurantInfo, fmt.Sprintf("이름: %s\n주소: %s\n전화번호: %s\n특징: %s\n반경: %s\n%s\n",
name,
item["newAddressList"].(map[string]interface{})["newAddress"].([]interface{})[0].(map[string]interface{})["fullAddressRoad"].(string),
item["telNo"].(string),
desc,
radiusStr,
googleMapURI,
))
}
return restaurantInfo, nil
}
func restaurantInfo(requestData *RequestData) string {
message := "맛집을 찾을 수 없네요"
poi, err := getPOIByKeyword(requestData.Msg)
if err != nil {
return message
}
restaurantInfo, err := findRestaurants(poi.Latitude, poi.Longitude)
if err != nil {
return message
}
restaurantInfoStr := strings.Join(restaurantInfo, "\n")
message = fmt.Sprintf("To.%s님\n[오늘의 맛집(%s)]\n%s\n",
requestData.SenderName, requestData.Msg, restaurantInfoStr)
return message
}
func sendToTelegram(message string) error {
bot, err := tgbotapi.NewBotAPI(telegramBotToken)
if err != nil {
return err
}
msg := tgbotapi.NewMessage(telegramChannelID, message)
msg.ParseMode = "HTML"
_, err = bot.Send(msg)
return err
}
func tmapRestaurant(c *gin.Context) {
requestData := &RequestData{}
if err := c.ShouldBindJSON(&requestData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 200, "msg": "JSON data parsing error"})
fmt.Printf("JSON data parsing error:", err)
return
}
fmt.Printf("Message[%s] SenderName[%s]\n", requestData.Msg, requestData.SenderName)
var message string
message = restaurantInfo(requestData)
// 메시지 전송
sendErr := sendToTelegram(message)
if sendErr != nil {
fmt.Printf("Today 메시지 전송 중 오류 발생:", sendErr)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "Message sent successfully"})
}
func main() {
//Gin 라우터 설정
r := gin.New()
r.POST("/tmap/restaurant", tmapRestaurant)
//서버 실행
go func() {
err := r.Run(":" + "18082")
if err != nil {
fmt.Printf("Failed to start server:", err)
}
}()
select {}
}코드 작성을 완료했으면, 아래와 같이 GoLang 프로그램을 빌드하고
티맵 OpenAPI를 활용한 맛집정보 텔레그램 봇 메시지 전송 서버를 실행합니다.

그리고, 기능이 정상적으로 구현되었는지 insomnia 툴을 사용해서 테스트 요청을 전송합니다.
msg : SKT타워
sender_name : 매직

그러면 위와 같이 정상적으로 전송했다는 200 OK 코드를 받게되고요...
아래와 같이 텔레그램봇이 있는 방으로 메시지가 수신됩니다.

그리고 명동교자 본점의 구글지도보기 링크를 클릭하면 아래와 같이 구글 지도로도 위치를 확인할 수 있습니다.

여기까지가 제가 한번 Tmap openapi 를 활용해서 golang 과 gin 프레임워크 으로 구현한 주변맛집 검색 기능입니다.
항상 믿고 봐주셔서 감사합니다.
간단하게 오늘의 블로그에 대해서 저만의 생각을 정리해보자면요.
이 golang 프로그램을 잘이용하면 특정 위치기반으로 검색하고싶은 음식점정보를 정리해서
텔레그램 메시지로 전송하고 공유 할 수 있을것 같고요.
티맵에서 지원하는 음식점 특징을 보고 맛집선정에 도움을 받을 수 있을것 같네요.
오늘의 블로그는 여기까지고요
항상 믿고 봐주셔서 감사합니다.
그럼 오늘하루도 건강하시고 행복한 하루되세요~
목표
나의 강점을 바탕으로 나의 일을 잘해냄으로써 타인과 사회를 아릅답게 만든다.
현재 내가 가진 능력으로 누군가에 도움이 될 수 있을까? 에 대해서 항상 생각하기
나는 블로그 생태계에서 IT 테크관련 파워블로거가 반드시 된다!
유튜브 시장(?)을 호령하는 100만 유튜버가 반드시 된다!! (feat. 100만 유튜버가 반드시 될 매직!!)
나는 꾸준히 공부하고 공부한것을 실천하는 창의적인 개발자가 된다.! (feat. devocean 개발&운영자가될 매직!!)
목표를 이루기 위한 실천방안
꾸준한 블로깅/기록법/독서법으로 넘버원이 아닌 온리원이 되보자.
천사불여일행(千思不如一行)을 항상생각하며 체화 및 각인시키자.
"천번 생각하는것보다 한번 행동하는 것이 더 중요하다."
기기일약 불능십보(騏驥一躍 不能十步) / 노마십가 공재불사(駑馬十駕 功在不舍)
천리마도 한번에 열걸음을 뛸 수 없고, 느리고 둔한말이라도 열흘이면 하룻길을 간다.
모든 실수에는 마술이 숨어 있다. 따라서 나는 실수하면 실수할수록, 그런 실수에서 더 많이 배울수록 삶에서 더 많은 마술을 갖는다.
조금이나마 제 글이 도움이 되셨다면, 아래 배너 링크를 통해서 네이버인플루언서 팬이되주시면 제가 컨텐츠를 생산(?)하는데 큰 도움이 될것 같습니다. ^^;
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.