팀 프로젝트 등산로 API 구현기 -1

훈이·2022년 12월 23일
1
post-custom-banner

팀 프로젝트 회고록 이동


내가 부트캠프에서 했던 팀 프로젝트는 등산 할 크루들을 모으는 일회성 모집 사이트이다.
등산 크루들을 모으는 사이트이기 때문에 어느 산의 등산로를 등반할지와 등산로에 대한 경로를 보여주는게 중요했다.

그래서 백엔드에서는 내가 등산로에 관한 API를 담당하게 되었다. 내가 맡은 등산로 API는 각각 산들에 속한 등산로의 좌표들을 뽑아와 프론트엔드에게 줘야했다.

그래서 팀 프로젝트 당시 나는 오픈 API를 통해 등산로들의 정보와 좌표를 가져오려고 했다.
그래서 공공데이터포털 V월드에서 산림청에서 제공하는 전국 등산로 정보라는 오픈 API가 있어서(V월드 등산로 API 링크) 옳다구나! 하고 이걸 쓰면 되겠구나! 하고 생각했다. 하지만 이것이 나의 멘탈이 붕괴되고 지옥의 시작이 될 줄은 이때만 해도 전혀 상상하지 못했다.

해당 오픈 API의 사용법이나 설명서가 보이지 않아서 API 실데이터 검색이라는 사용 예가 있어서 보기로 하였다.

위의 이미지에서 요청파라미터로 geomFilter와 attrFilter, crs가 입력되었고 검색결과로 산명칭과 공간정보객체 등등 여러 정보가 나왔다. 근데 입력값이 이해가 안가 파라미터들에 대한 설명을 보았다.


위의 이미지는 필수 파라미터들에 대한 정보와 설명이 있었다. 일단 필수로는 request와 data, geomFilter, attrFilter, crs가 있엇다. attrFilter와 crs는 필수는 아니지만 attrFilter는 범위를 좁히기 위해서는 필수라고 생각하여 넣었으며, crs는 반환하는 좌표들을 카카오맵이 쓰는 EPSG:5181 또는 EPSG:4326으로 변환하기 위해 필요하다고 생각하여 넣었다.

여기서 나에게 가장 큰 시련을 준 건 geomFilter였다. 지오메트리 필터라고 부르는데 포맷으로 POINT, LINESTRING, POLYGON, MULTIPOLYGON가 있었다. 검색을 해보니 지도 서비스를 구성하는 백터 데이터라고 하는데 간략하게 설명 해보자면,
Point : 좌표 공간에서 한 지점의 위치를 표시
LINESTRING : 다수의 Point를 연결해주는 선분
POLYGON : 다수의 선분들이 연결되어 닫혀 있는 상태인 다각형
MULTIPOLYGON : 다수 개의 Polygon 집합

그래서 등산로의 경로가 있으면 데이터에 하나 하나의 Point들이 있고 그걸 선으로 이으면 Linestring이 되며 등산로의 경로가 된다고 생각하였다. 근데 문제는 필수 파라미터로 geomFilter가 있어서 대체 어떻게 저 좌표를 파라미터로 넣을 수 있을까 고민하였다. 그래서 실 사용예제에 있는 LINESTRING(13133057.313802 4496529.073264,14133023.872602 4496514.7413212)에 대해서 많은 고민을 하였는데 저 좌표를 좌표 변화 사이트에서 다양한 crs로 변경하여 구글맵, 카카오맵에 검색하는 등 소위말해 별짓을 다 해봣다.

근데 나에게 멘붕을 준건 지도에 안뜨거나 빗나가거나 하는 문제였다. 그래서 코딩공부가 아니라 좌표공부를 열심히 하기도 했고, 팀 프로젝트 점검을 받을 때 개발자 분들께 질문도 드렸는데, 개발자 분들도 안되면 포기하거나 다른 식으로 하자고 하셨다.
그래도 오기가 생겨 많은 고민을 하였는데, 우연히 geomFilter가 필수지만 빼도 상관이 없다는 걸 우연히 알게되어 attrFilter를 이용하여 여러 조건을 줘서 검색하자라는 생각을 하게되었다.
attrFilter는 속성조회를 위한 조건검색을 정의하며 다양한 조건을 넣을 수 있었다.

그래서 아래와 같은 코드를 만들었다.

// 읍면동 코드 오픈 API
  async getEmdCdInfo({ address }) {
    const emdCdInfo = await axios({
      url: 'http://api.vworld.kr/req/data',
      method: 'GET',
      params: {
        key: '21C35C47-E16F-3811-A71E-F3E339A7D1AE',
        attrFilter: `full_nm:=:${address}`,
        data: 'LT_C_ADEMD_INFO',
        request: 'GetFeature',
        domain: 'https://develop.wetrekking.kr',
      },
      headers: {
        'Content-type': 'application/json',
      },
    }).catch((err) => {
      throw err;
    });

    const emdCd =
      emdCdInfo.data.response.result.featureCollection.features[0].properties
        .emd_cd;
    // console.log(emdCd);
    return emdCd;
  }

  // 등산로 오픈 API
  async getTrekkingInfo({ addressEmdCd, mountainName }) {
    const arr = [];
    const getTrekkingInfo = await axios({
      url: 'http://api.vworld.kr/req/data',
      method: 'GET',
      params: {
        key: '21C35C47-E16F-3811-A71E-F3E339A7D1AE',
        attrFilter: `mntn_nm:=:${mountainName}|emdCd:=:${addressEmdCd}`,
        crs: 'EPSG:4326',
        data: 'LT_L_FRSTCLIMB',
        domain: 'https://develop.wetrekking.kr',
        request: 'GetFeature',
      },
      headers: {
        'Content-Type': 'application/json',
      },
    }).catch((err) => {
      throw err;
    });

    const wetrekking =
      getTrekkingInfo.data.response.result.featureCollection.features;

    for (let i = 0; i < wetrekking.length; i++) {
      const data = wetrekking[i].geometry.coordinates[0];

      for (let j = 0; j < data.length; j++) {
        const temp = data[j][1];
        data[j][1] = data[j][0];
        data[j][0] = temp;
      }

      arr.push(data);
    }
    const result = {
      mountainName,
      coordinate: arr.flat(),
    };

    return result;
  }

나는 파리미터로 attrFilter에 산의 이름과 해당 산의 읍면동을 입력해서 검색 결과에 맞는 등산로 들이 나오게 만들었다. 읍면동 코드 또한 오픈 API를 이용하여 구현하였다.

위의 결과는 Playground로 위의 코드로 조회를 해본 결과인데 저렇게 주소와 산의 이름을 치면 좌표와 산의 이름이 나왔다.

하지만 저 API의 큰 단점은 산의 주소를 정확하게 알아야 하며, 지리산 같이 여러 도시에 걸쳐져 있는 경우 어느 주소를 입력해야 하는지 잘 모르는 단점이 있었다. 그리고 제일 큰 문제는 오른쪽의 좌표들 중 몇개를 구글지도와 카카오지도에 넣어봤는데 좌표가 안나오는 경우가 있거나 엉뚱한 지점이 찍히는 경우가 많았다.

이렇게 나의 1차 시도는 실패로 끝났다...........

참고한 사이트 : https://sparkdia.tistory.com/24

profile
백엔드 개발자가 되자!
post-custom-banner

0개의 댓글