본문 바로가기

Frontend

공연 통계 오픈 api 활용해보기

처음에 내가 오픈마켓을 기획하면서 만들고자 한 서비스는 뮤지컬 굿즈 판매 마켓이라는 정체성을 가져가면서 배너 부분에 뮤지컬 주간 랭킹과 공연 정보도 함께 보여주고 싶었다.
 
뮤지컬, 연극 등 공연과 관련된 공공 API를 제공하는 곳은 공연예술통합전산망이라는 홈페이지였는데 아쉽게도 예매 랭킹은 제공되지 않았다. 당시에는 공연 목록, 공연장 목록,지역별 판매액 등 다양한 정보가 제공되었지만 예매 순위는 전혀 제공이 되지 않아서 원하는 베너 디자인을 포기하고 있었다.
그러던 와중 메일을 하나 받았다.

이 제목을 보고 설마 내가 원하는 데이터가 추가된건가?! 싶어 두근두근하며 확인했다.

 

완전 운이 좋게도 예매 통계가 신설되어서 일자별로 통계 확인이 가능했다(주간, 월간도 당연히 가능)
어떻게 이 타이밍에 내가 원하는 데이터가 추가되지? 내 마음을 읽으셨나.. 진짜 다행이었다. 베너를 어떤걸로 대체해야 할지 난감했는데ㅠㅠ 추가해준 개발자님에게 압도적 감사를... 이건 나를 위한 데이터다 생각해서 당장 추가하기로 했다.
이외에도 유용하게 쓰일만한 API가 많이 추가되었으니 필요하신 분들은 사용하시면 좋을듯 합니당
 
https://www.kopis.or.kr/por/cs/openapi/openApiList.do?menuId=MNU_00074&tabId=tab2_1

 

공연예술통합전산망

예술경영지원센터 운영, 공연 예매 정보 집계 및 DB, 예매상황판, 공연통계 등 제공.

www.kopis.or.kr:443

 
여기에서 제시된대로 기본 요청 URL에 요청 변수를 추가해서 요청했다.
나는 뮤지컬 주간 예매 랭킹을 보여주고 싶었고 지역구분은 하지 않고 싶었기 때문에 area를 제외한 속성을 넣어서 다음과같이 요청했다.
참고로 서비스 키는 홈페이지에서 신청하면 메일로 바로 받아볼 수 있다.

요청 URL

🔥문제상황

데이터를 가져오면서 두가지의 문제를 겪었다.
첫번째는 CORS 에러이다.
처음에는 무슨 오류인지 몰랐는데 에러메세지를 읽어보니 눈에 띄는 CORS라는 글자! 
CORS에러에 대해서 찾아봤더니 서버와 클라이언트의 요청 도메인이 달라서 발생하는 오류라고 한다.
이를 정석으로 해결하는 방법은 서버에서 Access-Control-Allow-Origin 헤더에 url을 추가해주는건데 지금은 외부 API를 불러오는 것이기 때문에 불가능했다.
 
그래서 이럴 경우 해결방법은 클라이언트와 서버 간에 통신을 연결해주는 프록시 서버를 만들어주거나 이미 만들어진 프록시 서버를 빌려오면 된다. 

크롬에서 제공하는 CORS 에러 해결 프로그램을 설치해서 임시방편으로 해결했다. 
일단 이 프로그램을 설치하고 간단하게 설정해주면 해결되지만 이후에는 프록시 서버를 생성해서 해결해보고 싶다.
 
두번째 문제는 데이터가 xml형태로 제공된다는 것이었는데 json형태로 변환하기 위해서 따로 xmlToJson 함수를 작성해서 변환해줬다. hook으로 만들어주려고 했는데 훅은 재귀함수 형태로 작성하면 왜인지 모르게 에러가 나더라. 그래서 일반함수로 작성해서 xml로 받아온 데이터를 변환해줬다.

export const xmlToJson = (xml) => {
	// xml => json 변환 xmlToJson함수
	// Create the return object
	let obj = {};

	if (xml.nodeType == 1) {
		// element
		// do attributes
		if (xml.attributes.length > 0) {
			obj['@attributes'] = {};
			for (let j = 0; j < xml.attributes.length; j++) {
				let attribute = xml.attributes.item(j);
				obj['@attributes'][attribute.nodeName] = attribute.nodeValue;
			}
		}
	} else if (xml.nodeType == 3) {
		// text
		obj = xml.nodeValue;
	}

	// do children
	// If all text nodes inside, get concatenated text from them.
	let textNodes = [].slice.call(xml.childNodes).filter(function (node) {
		return node.nodeType === 3;
	});
	if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
		obj = [].slice.call(xml.childNodes).reduce(function (text, node) {
			return text + node.nodeValue;
		}, '');
	} else if (xml.hasChildNodes()) {
		for (let i = 0; i < xml.childNodes.length; i++) {
			let item = xml.childNodes.item(i);
			let nodeName = item.nodeName;
			if (typeof obj[nodeName] == 'undefined') {
				obj[nodeName] = xmlToJson(item);
			} else {
				if (typeof obj[nodeName].push == 'undefined') {
					let old = obj[nodeName];
					obj[nodeName] = [];
					obj[nodeName].push(old);
				}
				obj[nodeName].push(xmlToJson(item));
			}
		}
	}

	return obj;
};

 

이렇게 해서 요청하면 json형태로 잘 받아올 수 있다.

요청해서 받아온 데이터는 50위 순위까지 제공이 되었다. 나는 베너에는 10위까지만 보여주고 싶었기 때문에 조건문을 달아서 인덱스가 10 미만인 경우만 화면에 보여주도록 했다.

이렇게 하면 원하는 대로 10위까지만 잘 불러올 수 있다. 음하하
여기서 디자인은 캐러셀 형식으로 좀 수정할 예정! 
그리고 날짜도 매일 바뀌어서 요청해야하므로 Date객체로 요청해서 보여주도록 수정할 예정이다.