본문 바로가기
후기🔥/회고록

잡다에서 기업 정보를 수집하는 방법

by 안주형 2023. 12. 28.

들어가며

안녕하세요, 마이다스인에서 AI 역량검사 채용 플랫폼 '잡다'를 개발하고 있는 백엔드 개발자 안주형입니다. 올해 5월부터 저는 사내에서 '기업 허브'라는 신규 프로젝트를 혼자 담당하게 되었습니다. 이 프로젝트를 통해, 기업 정보를 수집하는 방식을 단순히 NICE만을 사용하던 기존 방식에서 NICE, 금감원, 국민연금공단, 금융위원회, 카카오 API 및 FTP 데이터 등 다양한 데이터 소스를 통합하는 방식으로 변화시켰습니다. 그리고 이로 인해 연간 비용을 기존 대비 75%(약 1700만 원) 절감할 수 있었습니다.

이 글에서는 프로젝트를 진행하며 겪은 경험과 느낀 점에 대해 회고하려고 합니다.(본 게시글의 내용에 대외비에 해당하는 내용은 포함되어 있지 않으며 사내에서 검토된 포스팅입니다.)

 

 

기존의 문제점

'잡다'에서는 취업 준비생들에게 기업에 대한 다양한 정보를 제공하기 위해 '기업정보관'이라는 페이지를 운영하고 있습니다. 이 페이지에서는 다음과 같은 정보들을 제공하고 있습니다.

  • 기본 정보: 기업명, 기업 로고, 홈페이지 주소, 위치, 대표자 명, 기업 규모 등
  • 재무 정보: 최근 4년간의 매출액, 영업이익 등
  • 직원 정보: 월별 총 직원 수, 월별 입사자 수, 월별 퇴직자 수, 평균 근속 연수
  • 연봉 정보: 평균 연봉, 동종 업계 평균 연봉
  • 기타: 리뷰, 강점, 장점 등

그리고 이러한 정보들은 이전까지는 나이스 평가정보와의 유료 계약을 통해 API를 제공받아 데이터를 수집하고 있었습니다. 하지만 기존의 방식에는 크게 두 가지 문제점이 있었는데 다음과 같습니다.

 

첫째, 한 기업의 정보를 불러오기 위해 NICE API를 과도하게 되어, 비용이 과도하게 지출되는 문제.

NICE에서 하나의 기업의 정보를 불러오기 위해선 아래와 같이 총 40번의 API 호출이 필요했습니다.

  • 3개년 재무정보: 연도별 재무정보 API를 3번 호출
  • 3개년 월별 직원 정보: 월별 직원 정보 API를 36번 호출
  • 기업 기본 정보: 기업 기본정보 API를 1번 호출

여기서 문제점은 NICE와의 계약이 월별로 제한된 API 호출 횟수를 정하고, 그 이후의 호출은 건당 300원이 부가되는 구조였다는 점입니다.

둘째, 동일한 기업 정보 데이터를 여러 팀에서 독립적으로 NICE API를 호출하여 관리.

취업 준비생들에게 정보를 제공하는 '잡다(B2C) 페이지'뿐 아니라, 인사담당자들이 사용하는 'ATS 페이지인 잡다(B2B)'를 개발하는 팀 또한 기업 정보를 관리하기 위해 별개의 DB를 가지고 NICE API를 호출하고 있었습니다.

즉, 하나의 기업 정보를 업데이트하기 위해선 각 팀마다 총 40번의 NICE API 호출이 필요했으며, 이는 최악의 경우 하나의 기업 정보를 불러오는 데 12,000원의 비용이 들어가는 것과 같았습니다. 잡다에서는 약 십만 개의 기업데이터를 관리하고 있었기 때문에 기존의 방식을 계속 유지했다면 언젠가는 나이스로부터 누군가가 몇 년 동안 무급으로 일해야 할 만큼의 비용을 청구받았을 것입니다.

 

 

해결방안 도출

이러한 문제점들을 해결하기 위해서, 아래 두 가지 방안을 도출하고 적용하기로 결정했습니다.

 

  1. 유료인 NICE API는 최소한으로 사용하고, 그 외의 필요한 기업 정보는 무료인 공공 API를 활용하여 수집한다.
  2. 전사 공용으로 사용할 수 있는, 기업 정보만을 수집하고 조회하는 통합 API 서버인 '기업허브'를 구축하여 관리한다.

비용 절감이 주요 목적이었기 때문에, 기업 허브 API 서버의 환경은 최소한의 스펙으로 DevOps 팀에 요청하여 구축하였습니다. 그리고 후에 자세히 서술하겠지만 NICE API를 완전히 걷어내지 못한 이유는 공공 API 같은 경우 상대적으로 규모가 작은 기업들에 대한 데이터가 부족하고, 데이터 업데이트 주기가 느린 편이었기 때문입니다.

또한 API나 메세징을 통해 각 데이터의 동기화를 맞추는 것이 아니라 통합 API 서버를 구축한 이유는 동일한 데이터를 불러오는 로직과 로깅 관리를 한 곳에서 처리하고, 추후에 또 다른 팀이 기업정보를 사용할 가능성을 고려하여 새로 구축하는 것이 효율적이라 생각했기 때문입니다.

 

 

공공 API 조사

먼저 다른 채용 플랫폼들은 어떤 방법으로 기업 정보를 수집하고 있는지 조사를 시작했습니다. 대부분의 플랫폼들이 데이터의 출처를 명시해 놓아 조사하기는 수월했는데, 6개의 플랫폼을 살펴본 결과 대표적으로 나이스(NICE), 금융감독원(FSS), 금융위원회(FSC), 그리고 국민연금공단(NPS) 등에서 데이터를 제공받고 있는 것을 확인할 수 있었습니다. 그리고 더 나아가 중소벤처 24, 알리오, 클린아이 등에서도 데이터를 얻을 수 있는 것을 확인했습니다.

각 데이터 출처의 웹사이트는 다음과 같습니다.

각 공공 데이터마다 제공하는 정보가 서로 중복되는 부분도 있지만, 대부분의 경우 아래와 같이 특정 데이터를 특정 출처에서 사용하고 있었습니다. 그리고 저희도 아래의 출처 그대로 특정 데이터를 적용하기로 결정했습니다.

  • 나이스(NICE): 기본 정보
  • 금융감독원(FSS): 재무 정보, 연봉 정보, 직원 정보
  • 금융위원회(FSC): 연봉 정보, 직원 정보
  • 국민연금공단(NPS): 직원 정보

 

 

공공 API 활용

기획단계만 보면 API를 그대로 호출하여 데이터를 저장하고 보여주기만 하면 될 것 같지만, 실제 적용 과정에서는 생각보다 여러 시행착오와 고민을 겪게 됩니다.

각 공공 API를 한 번씩 세밀하게 살펴봅시다.

금융감독원(FSS) 고유번호 조회

먼저 금융감독원(FSS, 이하 '금감원')에서 제공하는 API를 사용하려면, 모든 API 요청에서 금감원에서 정의한 기업의 고유번호가 필수 요청인자로 들어가야 합니다.

고유번호조회 API. 필수 요청 인자에 corp_code(고유번호)가 포함되어있다.

문제는 금감원 API를 통해서는 고유번호를 얻을 수 있는 방법이 '고유번호조회 API' 밖에 없다는 점인데, 명세를 보면 매우 불편하다는 것을 알 수 있습니다. 해당 API는 특정 기업에 대한 고유번호를 제공하는 것이 아니라 다음과 같이 모든 기업의 고유번호가 기록된 XML 파일을 압축된 ZIP 파일 형태로 제공하기 때문입니다.

CORPCODE.xml

심지어 이 XML 파일에서 고유번호와 매핑된 값이 사업자등록번호나 법인등록번호가 아닌 기업명이라는 점이 문제인데, 기존에 '(주)마이다스아이티', '(유)구글코리아' 등과 같은 형식으로 기업명을 저장하고 있다면 고유번호를 저장하기 위해 파싱 과정이 필요하게 됩니다. 또한 'SK하이닉스'를 '에스케이하이닉스'와 같이 기업명의 영문을 한글로 기록해 놓은 케이스의 경우에는 이를 다시 변환하는 과정이 추가로 필요합니다.

이런 점들로 인해 고유번호를 저장하는 과정이 상당히 까다로우며, 기업명을 파싱하고 변환하는 과정에서 예상치 못한 케이스까지 고려하다 보면, 해당 고유번호가 진짜 해당 기업에 해당하는 번호로 저장되는지에 대한 데이터 무결성을 의심하게 됩니다.

기업개황 API. 응답값에 사업자등록번호와 법인등록번호가 있다.

무결성을 조금이나마 지키기 위해서는 기업개황 API를 통해 XML파일에 존재하는 모든 고유번호를 기준으로 한 번씩 호출하여 응답값으로 내려오는 사업자등록번호와 법인등록번호로 교차검증을 진행할 수 있습니다. 하지만 이 과정에서도 국내기업을 기준으로 사업자 등록번호가 "123456789"와 같이 10자리의 숫자만 오는 것도 있고, "123-45-67890"와 같이 하이폰(-)이 포함된 형태로 오는 경우와, null이나 빈 문자열("")로 오는 경우도 있기 때문에 많은 예외케이스를 고려해야 합니다.

금감원의 고유번호를 얻기 위한 또 다른 방법으로는 금융위원회(FSC) API를 통해 법인등록번호로 고유번호를 얻는 방법이 있습니다. 이에 대해서는 아래에서 서술하겠습니다.

 

금융감독원(FSS) 재무정보 & 인원정보 조회

이제 고유번호를 얻었기 때문에 재무정보조회 API직원현황 API를 통해서 재무정보와 연봉정보 등을 조회할 수 있습니다. 하지만 이 API들을 사용할 때도 다양한 예외케이스들을 고려해야 하는데, 특히 직원현황 API의 경우가 고려해야 할 점들이 많습니다.

직원현황 API 명세.

명세 부분을 확인 후, 삼성전자의 직원현황을 조회했을 때 응답은 다음과 같습니다.

{
    "status": "000",
    "message": "정상",
    "list": [
        {
            "rcept_no": "20230307000542",
            "corp_cls": "Y",
            "corp_code": "00126380",
            "corp_name": "삼성전자",
            "sexdstn": "남",
            "fo_bbm": "DX",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "38,023",
            "rgllbr_abacpt_labrr_co": "-",
            "cnttk_co": "333",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "38,356",
            "avrg_cnwk_sdytrn": "16.0",
            "fyer_salary_totamt": "-",
            "jan_salary_am": "-",
            "rm": "-"
        },
        {
            "rcept_no": "20230307000542",
            "corp_cls": "Y",
            "corp_code": "00126380",
            "corp_name": "삼성전자",
            "sexdstn": "여",
            "fo_bbm": "DX",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "11,948",
            "rgllbr_abacpt_labrr_co": "223",
            "cnttk_co": "94",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "12,042",
            "avrg_cnwk_sdytrn": "12.8",
            "fyer_salary_totamt": "-",
            "jan_salary_am": "-",
            "rm": "-"
        },
        {
            "rcept_no": "20230307000542",
            "corp_cls": "Y",
            "corp_code": "00126380",
            "corp_name": "삼성전자",
            "sexdstn": "남",
            "fo_bbm": "DS",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "51,079",
            "rgllbr_abacpt_labrr_co": "-",
            "cnttk_co": "126",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "51,205",
            "avrg_cnwk_sdytrn": "10.5",
            "fyer_salary_totamt": "-",
            "jan_salary_am": "-",
            "rm": "-"
        },
        {
            "rcept_no": "20230307000542",
            "corp_cls": "Y",
            "corp_code": "00126380",
            "corp_name": "삼성전자",
            "sexdstn": "여",
            "fo_bbm": "DS",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "19,777",
            "rgllbr_abacpt_labrr_co": "181",
            "cnttk_co": "24",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "19,801",
            "avrg_cnwk_sdytrn": "10.7",
            "fyer_salary_totamt": "-",
            "jan_salary_am": "-",
            "rm": "-"
        },
        {
            "rcept_no": "20230307000542",
            "corp_cls": "Y",
            "corp_code": "00126380",
            "corp_name": "삼성전자",
            "sexdstn": "남",
            "fo_bbm": "성별합계",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "89,102",
            "rgllbr_abacpt_labrr_co": "-",
            "cnttk_co": "459",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "89,561",
            "avrg_cnwk_sdytrn": "12.9",
            "fyer_salary_totamt": "12,408,336,000,000",
            "jan_salary_am": "143,000,000",
            "rm": "-"
        },
        {
            "rcept_no": "20230307000542",
            "corp_cls": "Y",
            "corp_code": "00126380",
            "corp_name": "삼성전자",
            "sexdstn": "여",
            "fo_bbm": "성별합계",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "31,725",
            "rgllbr_abacpt_labrr_co": "404",
            "cnttk_co": "118",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "31,843",
            "avrg_cnwk_sdytrn": "11.5",
            "fyer_salary_totamt": "3,189,421,000,000",
            "jan_salary_am": "110,000,000",
            "rm": "-"
        }
    ]
}

직원현황 API의 응답값을 살펴보면, 다음과 같은 점들을 고려해야 합니다.

  1. 삼성전자 전체에 해당하는 값들만 나오는 것이 아니라, 'fo_bbm'을 통해 사업 부문별로 나온다.
  2. 'fo_bbm(사업 부분)'에 '성별합계'라는 값을 통해 전체 부문을 확인할 수 있다.
  3. 데이터가 없는 경우 '-' 처리되어 있다.
  4. 연봉 정보와 같은 특정 값들은 ','로 처리되어 있다.

전처리는 했다고 가정하고, 삼성전자 전체에 해당하는 직원의 연봉 정보를 얻기 위해 'fo_bbm'이 '성별합계'이고, 'sexdstn'이 '남'과 '여'인 경우만 뽑아내어 아래의 식을 통해 계산할 수 있습니다.

(남자 1인 평균연봉 * 남자직원수) + (여자 1인 평균연봉 *여자직원수) / (남자직원수 + 여자직원수)

하지만 이러한 방식은 삼성전자와 같이 응답값이 내려올 때만 적용가능 한 것으로, 다른 기업을 조회하면 다음과 같이 응답값이 다르게 조회됩니다.

{
    "status": "000",
    "message": "정상",
    "list": [
        {
            "rcept_no": "20230315001173",
            "corp_cls": "Y",
            "corp_code": "00172291",
            "corp_name": "더존비즈온",
            "sexdstn": "남",
            "fo_bbm": "본사",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "1,083",
            "rgllbr_abacpt_labrr_co": "-",
            "cnttk_co": "20",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "1,103",
            "avrg_cnwk_sdytrn": "6년 2개월",
            "fyer_salary_totamt": "61,933,000,000",
            "jan_salary_am": "59,000,000",
            "rm": "-"
        },
        {
            "rcept_no": "20230315001173",
            "corp_cls": "Y",
            "corp_code": "00172291",
            "corp_name": "더존비즈온",
            "sexdstn": "여",
            "fo_bbm": "본사",
            "reform_bfe_emp_co_rgllbr": "-",
            "reform_bfe_emp_co_cnttk": "-",
            "reform_bfe_emp_co_etc": "-",
            "rgllbr_co": "631",
            "rgllbr_abacpt_labrr_co": "-",
            "cnttk_co": "24",
            "cnttk_abacpt_labrr_co": "-",
            "sm": "655",
            "avrg_cnwk_sdytrn": "4년 8개월",
            "fyer_salary_totamt": "27,731,000,000",
            "jan_salary_am": "47,000,000",
            "rm": "-"
        }
    ]
}

응답을 보면, 명세와 달리 '평균근속연수(avrg_cnwk_sdytrn)'가 'x년 x개월'로 응답되거나, 'fo_bbm'도 '성별전체'가 아니라 '본사'로 표기되는 등 예상과 다르게 나옵니다.

따라서 금감원의 데이터를 활용할 때는 명세에만 의존하여 개발하지 않고, 실제로 여러 응답값을 직접 확인하여 이에 따른 다양한 예외 케이스처리와 데이터를 정제한 후 사용해야 합니다. 또한 금감원의 경우 서비스의 안정적인 운영을 위하여 이용한도가 존재하니 이 부분도 꼭 참고해서 진행해야 합니다.

 

금융위원회(FSC)

금융위원회(FSC, 이하 '금융위')는 금감원의 상위 조직으로, 금감원은 기본적으로 금융위원회 산하의 특수법인입니다. 별도로 문서에 명시되어 있지는 않지만, 저장된 데이터 조회하여 살펴본 결과 연봉정보와 같이 양쪽에서 동일하게 얻을 수 있는 데이터의 경우 금감원에 있는 정보는 대부분 금융위 API에서도 조회가 가능했고, 반대로 금융위에서 조회되는 정보는 금감원 API를 통해 조회가 가능하거나 불가능한 경우가 있었습니다.

사용하면서 느낀 점은 금감원과 마찬가지로 상대적으로 큰 규모의 기업에 대한 데이터만 가지고 있었고, 작은 규모의 기업들에 대한 데이터는 잘 조회되지 않았습니다.

금융위의 기업기본정보 API를 사용하면, 법인 등록번호를 필수 요청값으로 하여 기업의 기본 정보와 함께 '금감원의 고유번호'와 '기업1인평균연봉'을 얻을 수 있습니다.

 

국민연금공단(NPS)

국민연금공단(NPS, 이하 '국민연금') API를 활용하면, 월별 직원 정보(총 인원 수, 입사자 수, 퇴직자 수)를 얻을 수 있습니다. 하지만 이를 활용가능한 데이터로 만들기 위해서는 약간의 전처리 작업이 필요합니다.

국민연금에서 월별 직원 정보를 얻기 위해서는 아래 세 API를 전부 활용해야 합니다.

  1. 사업장 기본정보 조회(식별번호)
  2. 상세 정보조회(총 직원수)
  3. 기간별 현황 정보조회(월별 취업자 수, 월별 퇴직자 수)

특히, 국민연금에서 특정 기업의 상세 정보와 기간별 현황 정보를 얻기 위해선, 금감원과 마찬가지로 국민연금에서 정의한 고유한 식별번호(seq)를 요청 인자로 보내야 합니다.

식별번호(seq)를 얻기 위한 사업장 '사업장 기본정보 조회 API'의 명세는 다음과 같습니다.

요청 변수에는 '사업자명'이 필수이고, '법정동코드'와 '사업자등록번호'는 옵션으로 들어갑니다. 필수값인 '사업자명'만 입력하고 요청하면 아래와 같은 데이터가 응답값으로 조회됩니다.

...
            <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202204</dataCrtYm>
                <ldongAddrMgplDgCd>30</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>200</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>124</ldongAddrMgplSgguEmdCd>
                <seq>39196607</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)-(일용)리모델링 3단계(응용공학동) 공사 냉난방기 구매설치</wkplNm>
                <wkplRoadNmDtlAddr>대전광역시 유성구 대학로</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>
            <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202202</dataCrtYm>
                <ldongAddrMgplDgCd>27</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>140</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>115</ldongAddrMgplSgguEmdCd>
                <seq>37992726</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)/ 일용/ 대구반야월초등학교 외 11교 냉난방기 구입 설치</wkplNm>
                <wkplRoadNmDtlAddr>대구광역시 동구 안심로49길</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>
            <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202110</dataCrtYm>
                <ldongAddrMgplDgCd>26</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>440</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>114</ldongAddrMgplSgguEmdCd>
                <seq>35956727</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)-(일용)부산테크노파크시스템냉난방기구매</wkplNm>
                <wkplRoadNmDtlAddr>부산광역시 강서구 과학산단1로60번길</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>
           <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202302</dataCrtYm>
                <ldongAddrMgplDgCd>41</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>117</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>101</ldongAddrMgplSgguEmdCd>
                <seq>44689804</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)</wkplNm>
                <wkplRoadNmDtlAddr>경기도 수원시 영통구 삼성로</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>
        </items>
...

자세히 보면 뭔가 이상합니다. 내려온 데이터에는 삼성전자 본사뿐만 아니라 일부 공장들의 정보까지 포함되어 있습니다. 따라서 원하는 본사 데이터만을 얻기 위해서는 사실상 '법정동코드'를 필수적으로 입력하여 요청해야 합니다.

이때 여기서 문제가 발생했습니다. 저희는 기업의 기본 데이터 정보는 NICE에 의존하고 있는데, 사용하고 있는 NICE API에서는 법정동코드는 제공하지 않았습니다. 국민연금에서 원하는 본사 데이터만을 얻기 위해선 법정동코드가 필수로 요구되는 만큼 이를 해결할 수 있는 방안을 찾아야 했습니다. 그리고 기업의 법정동 코드를 얻을 수 있는 두 가지 방법을 찾아냈습니다.

  1. 카카오 API
  2. 행정안전부_행정표준코드_법정동코드_API

이 두 API 모두 법정동코드를 얻을 수 있습니다. 카카오 API는 위경도 좌표를 이용하여 법정동코드를 찾을 수 있고, 행정안전부 API는 주소를 통해 법정동코드를 확인할 수 있습니다. 어느 것을 선택해도 얻을 수 있지만, 이미 공공 데이터로 인해 약간의 피로감을 느꼈고, 트래픽 제한이 크게 없는 카카오 API를 선택하여 법정동코드를 얻기로 결정했습니다.

이제 법정동 코드를 입력하여 조회하면, 다음과 같이 원했던 본사의 정보만 정확하게 얻어올 수 있습니다.

...
        <items>
           <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202302</dataCrtYm>
                <ldongAddrMgplDgCd>41</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>117</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>101</ldongAddrMgplSgguEmdCd>
                <seq>44689804</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)</wkplNm>
                <wkplRoadNmDtlAddr>경기도 수원시 영통구 삼성로</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>
           <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202303</dataCrtYm>
                <ldongAddrMgplDgCd>41</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>117</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>101</ldongAddrMgplSgguEmdCd>
                <seq>44689806</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)</wkplNm>
                <wkplRoadNmDtlAddr>경기도 수원시 영통구 삼성로</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>
            <item>
                <bzowrRgstNo>124810****</bzowrRgstNo>
                <dataCrtYm>202304</dataCrtYm>
                <ldongAddrMgplDgCd>41</ldongAddrMgplDgCd>
                <ldongAddrMgplSgguCd>117</ldongAddrMgplSgguCd>
                <ldongAddrMgplSgguEmdCd>101</ldongAddrMgplSgguEmdCd>
                <seq>44689809</seq>
                <wkplJnngStcd>1</wkplJnngStcd>
                <wkplNm>삼성전자(주)</wkplNm>
                <wkplRoadNmDtlAddr>경기도 수원시 영통구 삼성로</wkplRoadNmDtlAddr>
                <wkplStylDvcd>1</wkplStylDvcd>
            </item>           
        </items>
...

이제 '자료생성년월(dataCrtYm)'를 통해 해당 연도와 월을 파악하고 '식별번호(seq)'를 이용해 '사업장 상세정보 조회 API'를 통해 '총 직원 수'를, 그리고 '기간별 현황 정보조회 API'를 통해 '월별 취업자 수와 월별 퇴직자 수'를 얻을 수 있습니다 (왜 굳이 두 개로 구별했는지는 잘 모르겠습니다).

 

 

공공데이터포털 API의 고질적인 문제

금융감독원(opendart)에서 제공하는 API를 제외하고, 공공데이터포털(data.go.kr/api)에서 제공하는 금융위원회, 국민연금공단을 포함한 모든 API들은 개발자들을 괴롭히는 몇 가지 고질적인 문제들이 존재합니다.

1. 간헐적으로 'SERVICE_KEY_IS_NOT_REGISTERED_ERROR'가 발생

<OpenAPI_ServiceResponse>
    <cmmMsgHeader>
        <errMsg>SERVICE ERROR</errMsg>
        <returnAuthMsg>SERVICE_KEY_IS_NOT_REGISTERED_ERROR</returnAuthMsg>
        <returnReasonCode>30</returnReasonCode>
    </cmmMsgHeader>
</OpenAPI_ServiceResponse>

공공데이터 포털의 문의하기 섹션에는 'SERVICE_KEY_IS_NOT_REGISTERED_ERROR' 오류에 대한 설명이 있습니다. 이 오류는 잘못된 인증키를 사용하여 호출하거나, 인증 기관 서버와 동기화되지 않았을 때 발생한다고 명시되어 있습니다. 하지만 불과 방금 전까지 정상적으로 호출되던 동일한 인증키를 가지고 API를 호출했음에도 불구하고, 10번 중 1번은 '인증키가 올바르지 않다'는 오류가 간헐적으로 발생했습니다.

이 문제는 API Retry 전략을 통해 재요청하는 방법으로 해결했지만, 이와 같은 문제가 몇 년 전부터 많은 이용자들에 의해 질문 게시판에 문의되었음에도 불구하고 아직까지 해결되지 않은 것을 보면 포털 담당자들이 이 문제를 개선할 의지가 없어 보였습니다.

2. 요청의 결과는 오직 XML 형식의 바디 값을 통해서만 확인 가능

공공데이터포털의 API는 문제가 발생했을 경우, 해당 API가 JSON 타입의 응답 결과를 지원하더라도 오류 메시지는 무조건 XML 형식으로만 출력됩니다. 또한 오류의 종류에 관계없이 HTTP 상태 코드는 항상 200으로 응답되며, 오류에 대한 내용은 응답 결과에 포함되어 제공됩니다. 이로 인해 HTTP 상태 코드를 통해 1차적으로 문제를 구분하는 것이 불가능하고, 응답 본문을 반드시 확인하여 호출이 정상적인지 아닌지를 판별해야 하는 번거로움이 있습니다.

위와 같은 방식을 응답 방식을 SOAP protocol이라고 하는데, 사용하는 입장에서 장점은 사실 잘 모르겠습니다.
 
 

정리

기존에 하나의 기업 정보를 업데이트하기 위해 외부 API를 40번 호출하던 것이 82번으로 증가하였음에도 불구하고, 비용을 크게 절감할 수 있었습니다.

'후기🔥 > 회고록' 카테고리의 다른 글

2023년 회고  (10) 2024.01.14
잡다에서 선착순 이벤트를 구현한 방법  (3) 2023.08.31
NextStep TDD, Clean Code with Java 수료 후기  (2) 2023.06.05
2022년 회고  (13) 2023.01.27
넘블 디프백-프로젝트 회고록  (0) 2022.12.05

댓글