React에서 Open API XML 데이터 파싱하기 (with Express)

2023년 01월 04일

TOC

React

React 환경에서 XML로 구성된 공공데이터포털 API를 Express 서버로 파싱하기

XML 형식의 Open API

예전 프로젝트에서 공공데이터포털에 있는 XML(Extensible Markup Language) 형식의 API를 다룬 적이 있다. 데이터를 이용하여 원하는 형태로 구현하는 것 까지는 문제가 없었지만, GitHub Page, Vercel 등으로 프로젝트를 배포했을 경우 갖가지 문제에 부딪혔다. 특히 공공데이터포털에서 제공하는 API는 대다수가 XML 형식으로 되어 있다. 이 문제의 해결법은 아래에 설명해 놓은 방법만이 정답인 것은 아니겠지만 비교적 괜찮은 방법으로 성공한 것 같다.

GitHub에 새 저장소를 만들고, 생성한 저장소를 클론 후 react-app을 만들었다.

230104-01

$ git clone https://github.com/(github-id)/open-api-tutorial.git
$ cd open-api-tutorial
$ yarn create react-app open-api-tutorial

생성한 react-app에서 axios를 설치한다.

$ cd open-api-tutorial
$ yarn add axios

공공데이터포털에서 제공하는 국내 코로나 바이러스 현황을 받아볼 수 있는 API를 사용하였다.
공공데이터활용지원센터_보건복지부 코로나19 감염 현황 (현재 폐기됨)

XMLExtensible Markup Language 의 약자로, HTML과 비슷한 구조를 가진다.

230104-02

App.js에서 데이터를 콘솔에 출력하였다. 이 API는 startCreateDt, endCreateDt 파라미터로 데이터 범위를 지정할 수 있는데, Moment.js, Day.js와 같은 라이브러리를 사용하면 현재 날짜를 받아서 원하는 기간의 데이터를 받아볼 수 있다. 우선 테스트를 위해 날짜 라이브러리는 사용하지 않고 임의의 날짜를 입력해 주었다.

// src/App.js
import logo from "./logo.svg"
import "./App.css"
import { useEffect } from "react"
import axios from "axios"

function App() {
  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await axios.get(
          `http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson?serviceKey=${process.env.REACT_APP_API_KEY}&pageNo=1&numOfRows=10&startCreateDt=20221212&endCreateDt=20230103`
        )
        console.log(res.data.response.body.items.item)
      } catch (e) {
        console.log(e)
      }
    }
    fetchData()
  }, [])

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  )
}

export default App

react-app에 .env파일을 생성하고 다음과 같이 API KEY를 입력한다. GitHub에 .env파일이 올라가지 않게 .gitignore에 .env도 추가한다.

# .env
REACT_APP_API_KEY=APIKEY입력하는곳

# .gitignore
...
...
.env

yarn start로 실행시켜 확인하면 다음과 같이 지정한 범위의 코로나 데이터를 확인할 수 있다.
(콘솔에 두 번 출력되는 이유는 React의 StrictMode 때문이다.)

230104-03

작성한 그대로 GitHub Page에 배포하여 확인해 보자. gh-pages를 설치한다.

$ yarn add --dev gh-pages

package.json 내용을 추가 후, build, deploy를 하고 나면
https://(github-id).github.io/open-api-tutorial에서 페이지를 확인할 수 있다.

// package.json scripts에 추가
"predeploy": "yarn build",
"deploy": "gh-pages -d build"

// package.json에 따로 추가
"homepage": "https://(github-id).github.io/open-api-tutorial"
$ yarn build
$ yarn deploy

230104-04

페이지는 잘 나타났으나 데이터에서 Mixed Content Error가 발생한다.

230104-05

암호화된 HTTPS 페이지에 암호화되지 않은 HTTP를 통해 요청할 때 발생하는 에러라고 한다.
public/index.html에 HTTPS 변환 메타태그를 추가 후 다시 확인해 보면...

<meta
  http-equiv="Content-Security-Policy"
  content="upgrade-insecure-requests"
/>

230104-06

ERR_CERT_COMMON_NAME_INVALID 에러가 등장했다. SSL 인증서 관련 문제라고 한다. 이 프로젝트에서는 HTTPS 변환된 API가 존재하지 않아 에러가 발생했다는 뜻으로 보여진다.

따라서 다른 방법으로 구상한 게 웹 서버에 데이터를 파싱 후 웹 앱에 뿌리는 것이다.

Express Web Server

프로젝트 디렉터리에 server 디렉터리를 만들고 다음 라이브러리들을 설치했다.

$ yarn add express  # Node.js 서버 프레임워크
$ yarn add request  # HTTP 네트워크 요청
$ yarn add xml-js   # XML JSON 변환
$ yarn add cors     # Node.js CORS middleware
$ yarn add dotenv   # Node.js에서 환경변수 사용

server.js와 환경 변수 파일을 작성한다. react-app처럼 .gitignore을 만들고 node_modules , .env를 추가한다.

// server/server.js
require("dotenv").config()
const express = require("express")
const app = express()
const cors = require("cors")
const request = require("request")
const convert = require("xml-js")
const PORT = process.env.PORT || 5000

app.use(cors())

app.get("/api/data", (req, res) => {
  request(
    {
      url: `http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson?serviceKey=${process.env.REACT_APP_API_KEY}&pageNo=1&numOfRows=10&startCreateDt=20221212&endCreateDt=20230103`,
      method: "GET",
    },
    (error, response, body) => {
      const xmlToJson = convert.xml2json(body, { compact: true, space: 4 }) // xml to json
      res.send(xmlToJson)
    }
  )
})

app.listen(PORT, () => {
  console.log(`Listening on port ${PORT}`)
})
# .env
REACT_APP_API_KEY=APIKEY입력하는곳

# .gitignore
.env
/node_modules

터미널에서 server 디렉터리로 이동, node server.js를 실행하면 5050포트로 Express 서버가 실행된다. http://localhost:5050/api/data에서 API를 확인할 수 있다.

230104-07

코드 수정마다 매번 서버 재부팅을 하는 것은 귀찮기 때문에 nodemon을 설치하고, 명령어 간소화를 위해 package.jsonscripts를 추가한다.

$ yarn add nodemon
// server/package.json
  "scripts": {
    "dev": "nodemon server.js"
  }

이제 yarn dev 명령어로 서버를 실행시킬 수 있다.

만든 서버를 Heroku에 deploy 하는 것까지 글을 작성했지만 너무 글이 길어진 탓에 생긴 blog build의 문제거나, 페이지 색인 생성의 문제인지 search console에 url이 등록되지 않는 이슈가 생겼다. Heroku 배포 관련 내용은 다음 포스트에 써야할 듯 하다.


References

공공 데이터 API React에서 XML에서 JSON 변환!

Node.js에서 Request.js 사용하기. 네트워크 더 간결하게 작성하자! | by Harry The Great | 해리의 유목코딩 | Medium

[TS]React,Express 풀스택 웹 앱 배포하기(Netlify, Heroku) | by PEPPERMINT100 | Medium

Written by

yhuj79

🌱 Junior Developer