예전에 진행 했던 사이드 프로젝트를 하면서 처음으로REST API
를 사용했었다. 여러 일들이 있었는데 약간의 회고도 하면서 내가 어떤식으로 REST API
호출 하였고 어떻게 사용했는지 그리고 어떤 문제가 있었는지 한 번 정리해보려고 한다.
보면 홈 화면에만 3개의 API
를 호출해서 각 데이터를 가공하여 화면에 표시를 해야했다.
그래서.. 시작하자마자 문제에 부딪혔는데... 바로 API
를 호출하는 부분이었다.
API
...? REST API
?? 생소한 단어였다.. 그래서 이 때 당시에는 1~2번 검색해보고 이런게 있구나 라면서 한 번 훑고 넘어갔지만 명칭에 대해 이번에는 조금만 더 알아보고 넘어가자!
- REST ?
Representational State Transfer(REST)는 API 작동 방식에 대한 조건을 부과하는 소프트웨어 아키텍처이다. 복잡한 네트워크에서 통신을 관리하기 위한 지침으로 만들어졌다. REST 기반 아키텍처를 사용하여 대규모의 고성능 통신을 안정적으로 지원할 수 있다.- API ?
API 란 Application Programming Interface 의 약자이며, 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘이다.
그래서 두 개를 합친 REST API
란 것은.. REST
아케틱처 스타일로 설계 된 웹 API
를 말한다고 한다.
일단.. 어떤 API
를 말하는지 알아보았으니! 이제 한 번 사용 해볼까?
일단 공공기관 해수욕장 날씨 조회서비스 API 사이트에서 활용 가이드를 다운받아서 내용을 확인해보았다.
분명 위에서 봤던 REST 이긴 한데.. 여기에 GET 이라는걸 사용하나?
REST Method
- POST (POST를 통해 해당 URI를 요청하면 리소스를 생성)
- HTTP Request Message의 Body 부분에 데이터를 담아 전송한다.
GET과 비교하여 데이터 크기, 보안의 측면에서 좋을 수 있다.- GET (GET을 통해 해당 리소스를 조회, 해당 도큐먼트의 자세한 정보를 가져옴)
- 요청하는 데이터가 HTTP Request Message의 Header부분의 url에 담겨 전송된다. url의 ? 뒤에 데이터를 붙여서 요청을 보내는 것 (request)
REST API
에서 요청을 하는 2개의 Method
가 있는데 이러한 차이점이 있고, 해당 서비스는 GET
요청을 표준으로 하는 것 같았다.
XML
, JSON
교환 데이터 표준으로 XML
, JSON
두 가지를 사용한다고 되어있었다.
XML (EXtensible Markup Language)
- 웹, 애플리케이션, 데이터베이스, 컴퓨터 시스템 간의 정보교환을 지원
- HTML과 매우 유사한 문자 기반의 마크업 언어
- 데이터를 보여주는 목적이 아닌, 데이터를 저장하고 전달하는 목적
JSON (Javascript Object Notation)
- Javascript 객체 표기법
- 사람이 읽을 수 있는 텍스트 기반의 데이터 교환 표준
- XML의 대안으로 좀 더 쉬운 데이터 교환 및 저장의 목적
꽤 중요한.. 부분이다. 내가 요청을 해서 받는 데이터가 XML
일 경우 JSON
으로 변경해서 객체형식으로 사용하는 것이 좀 더 편리할 것이다. 이미지를 보면 XML
은 html처럼 보이고 JSON
은 javascript 처럼 보이니.. 우리가 응답 받은 데이터를 사용해야 한다면 javascript 객체 형식으로 표기된 데이터를 사용하는 것이 좀 더 편리하지 않을까?
대충 훑어 보았으니 이제 내가 사용할 데이터를 어떻게 호출하는지 알아보자.
문서 상단을 보면 Call Back URL이 적혀있다. 만약 해수욕장 단기예보 조회 데이터를 얻으려면 저 "Call Back URL"/serviceKey="??"/pageNo="??" 등의 예시 요청 메세지처럼 URL뒤에 정보들을 적어서 요청을 보내면 응답으로 해당 데이터를 아래와 같이 나에게 보내줄 것이다.
이제 이 API
를 자바스크립트 코드로 입력하여 호출해야 하는 방법을 찾아야 했다.
라이브러리 사용 방법들이 많이 보였지만.. 이 때는 왠지 라이브러리에 대한 무지로 두려움이 있어 순수 javascript를 이용한 방법을 찾게되었다.
(이런 마음은 당장 고쳐먹었다.. 라이브러리 제작하시는 천재 개발자분들 감사합니다 땡큐)
그러다가 데이터를 XML
로 받은 다음 JSON
변환을 javascript 코드만을 이용한 글을 보게 되었고, 코드를 가져와서 사용하였는데 그 코드는 아래와 같다.
아마 나랑 같은 고민을 하는 초보자들도 검색하다보면 한번 쯤은 보았을만한 코드라고 생각한다.
// XML -> JSON
export function xmlToJson(xml) {
let obj = {};
if (xml.nodeType == 1) {
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) {
obj = xml.nodeValue;
}
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;
}
// XML 데이터 요청
export async function getLCRiseSetInfo(lonString, latString, dateString)
const url =
'http://apis.data.go.kr/B090041/openapi/service/RiseSetInfoService/getLCRiseSetInfo';
const reqURL =
url + '?serviceKey=' + RISE_SET_INFO_SERVICE_KEY +`&longitude=${lonString}&latitude=${latString}&locdate=${dateString}&dnYn=Y`;
const response = await fetch(reqURL);
const xmlString = await response.text();
const XmlNode = new DOMParser().parseFromString(xmlString, 'text/xml');
const resultJSON = xmlToJson(XmlNode);
return resultJSON;
}
먼저 fetch
로 XML 데이터를 가져와서 저 길고 긴 XML to JSON 함수를 이용하여 JSON
으로 변환하여 사용하고, 데이터를 가공하여 화면에 표시해주는 방법으로 프로젝트를 마무리했었다.
같이 프로젝트를 진행했던 친구는 axios
를 사용하여 데이터를 바로 JSON
으로 받아서 사용했었고, 이번에 다시 프로젝트를 복기하기 위해 코드를 다시 보는 와중에 이 부분이 내 눈에 띄어서 나도 한 번 axios
를 사용하여 리팩토링하기로 한다.
서버와 데이터를 주고 받기 위한 HTTP 통신의 대표적인 3가지 fetch
, Ajax
, Axios
Ajax
fetch
JSON
으로 변환하는 작업이 필요하다.Axios
JSON
타입으로 자동 변환해준다.간단하게 이러한 차이점이 있었는데 fetch
보다는 axios
가 JSON
타입을 지원하는 API
에서는 초보자가 사용하기에 좀 더 나아보였다.
(쓰다보니 궁금해서 좀 더 자세히 공부해서 글을 써봐야겠다)
그래서 위의 api 요청 및 json 변환 코드를 axios
사용법으로 바꿔보았다.
export async function getXMLMidTiaFcstAxios(cityCode, baseDateTime) {
const result = await axios({
method: 'get',
url: 'http://apis.data.go.kr/1360000/MidFcstInfoService/getMidTa',
headers: { Accept: '*/*' },
params: {
serviceKey: SERVICE_KEY,
numOfRows: 10,
pageNo: 1,
dataType: 'JSON',
regId: cityCode,
tmFc: baseDateTime,
},
});
return result.data.response.body.items
fetch
로 API를 호출하는 방법보다 좀 더 내가 요청을 보내는 부분이 명확해 보인다는 생각이 들었다.
그리고 사용법도 생각보다 어렵지 않았는데 살펴보면 요청 주소를 보내기 위한 url
뒤쪽으로 params
키와 값들이 나열되어 요청을 보내진다.
만약 내가 요청하는 API
의 데이터 타입이 JSON
을 지원한다면 위의 코드로 바로 JSON
데이터를 받아서 바로 사용할 수 있을 것이다.
만약! XML
만 지원하는 API
라고 한다면 XmlToJson
라이브러리가 많으니 선택해서 사용하거나 위에 적혀있던 xmlToJson
함수를 사용하여 변환하면 된다.
나의 경우에도 일출, 일몰 데이터 API
가 XML
타입만 지원한다길래.. axios
로 호출하고 위의 코드를 이용하여 변환하였다.
export async function getLCRiseSetInfo(lonString, latString, dateString) {
const result = await axios({
method: 'get',
url: 'http://apis.data.go.kr/B090041/openapi/service/RiseSetInfoService/getLCRiseSetInfo',
headers: { Accept: '*/*' },
params: {
serviceKey: SERVICE_KEY,
longitude: lonString,
latitude: latString,
locdate: dateString,
dnYn: 'Y',
},
});
const xmlNode = new DOMParser().parseFromString(result.data, 'text/xml');
const resultJSON = xmlToJson(xmlNode);
return resultJSON.response.body.items.item;
}
위의 fetch
코드보다 좀 길어진 것 같지만, 데이터 요청 부분에 대한 코드 가독성이 더 괜찮아진 것 같다는 느낌이다. (어떤 method를 사용하여 어떤 데이터 요청을 params로 보내고 있지?..)
그리고 리팩토링 하던 도중에 문득 headers
부분의 기호가 무엇을 뜻하는지.. 갑자기 궁금해졌는데..
headers : { Accept: '*/*' }
header : { Accept } 는 MIME 타입으로 표현되는 클라이언트가 이해 가능한 컨텐츠 타입이 무엇인지 알려주는 것이라고 한다. 위와 같은 기호는 모든 타입을 뜻한다.
MIME ?
클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘이다.
웹에선 파일의 확장자가 의미가 없다보니 각 문서와 함께 올바른 타입을 전송하도록 서버가 정확하게 설정하는 것이 중요하다.
서버에 요청또는 응답 시 미리 타입을 알고 있으면 브라우저가 타입에 맞는 준비를 한다는 뜻이었다. 그래서 쌩뚱맞은 타입인 image/text
이런식으로 기입해보니 500 (Internal Server Error)
이런 에러가 발생했다.
기본 타입으론 type/subtype
을 사용한다고 하며, 대부분 이 타입으로 작성하면 문제가 없는 듯 하다.
MIME 타입은 굉~~장히 많았는데 호옥시 궁금하다면 문서를 참고해주시길!
MIME Type - MDN
지금까지 API를 처음 사용했을 때 상황부터 지금 다시 약간의 리팩토링을 거친 부분에 대해 주절주절 떠들어보았다.
그래도 이러한 경험이 있었으니 다음 프로젝트나 실무에 API를 사용한다면 겁 먹지 않고 차분히 해낼 수 있을 것 같다는 생각이 들었다.
.
.
.
.
.
참고 사이트
REST API란? - AWS
REST(GET, POST) 비교
Accept - MDN
MIME - MDN