AJAX 와 API
API
https://m.blog.naver.com/PostView.naver?blogId=kistiscienceon&logNo=222722915536&navType=by
AJAX & FETCH & AXIOS
Fetch
fetch("https://swapi.dev/api/people/1/")
.then((res) => {
console.log("RESOLVED!", res);
return res.json();
})
.then((data) => {
console.log(data);
return fetch("https://swapi.dev/api/people/2/");
})
.then((res) => {
console.log("SECOND REQUEST RESOLVED!");
return res.json();
})
.then((data) => {
console.log(data);
})
.catch((e) => {
console.log("ERROR!", e);
})
using the fetch api
const loadStarWarsPeople = async () => {
try {
const res = await fetch("https://swapi.dev/api/people/1/");
const data = await res.json();
console.log(data);
const res2 = await fetch("https://swapi.dev/api/people/2/");
const data2 = await res2.json();
console.log(data2);
}
catch (e) {
console.log("ERROR!!!", e);
}
}
using the fetch api (refatoring)
XHR로 요청을 생성하는 것보다 낫고, 가장 기본적인 형태의 URL을 제공하면 GET요청이 자동으로 실행된다.
그리고 프로미스를 반환하기때문에 .then 콜백을 추가하거나 .catch로 오류를 처리할 수 있다.
단점으로는 응답 객체의 본문이 자동으로 구문 분석되지 않는다는 점이고, ReadableStream이라서 .json을 호출해야한다.
json을 반환하도록 요청했다고 가정했을 때, .json호출로 json구문 분석 후 프로미스를 반환하고 처리되면 반환된 data를 콘솔에 출력하거나 추가 작업을 한다. 원하는 경우 비동기 함수를 사용해 코드를 리팩토링도 가능하다.
Axios
axios는 타사 라이브러리로 js의 네이티브 함수가 아니다.
axios는 HTTP 요청의 생성과 처리를 최대한 간소화할 목적으로 만들어졌다.
백그라운드에서는 동일하게 브라우저에 fetch 함수를 사용하지만 js에서 기본적으로 제공하는 함수가 아니므로 추가로 빌드 해야한다. 사용하려면 가져오기(import)해서 코드에 추가해야 한다.
한 단계가 추가되지만 요청이 많을 때는 확실히 그만한 가치가 있다.
axios는 node.js에서 작동하는 라이브러리다.
https://www.npmjs.com/package/axios
<script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
fetch("https://swapi.dev/api/people/1/")
.then((res) => {
console.log("RESOLVED!", res);
return res.json();
})
.then((res) => {
console.log("FETCH", res);
})
.catch((e) => {
console.log("ERROR", e);
})
axios.get("https://swapi.dev/api/people/1/")
.then((res) => {
console.log("AXIOS", res);
})
.catch((e) => {
console.log("ERROR", e);
})
결과
fetch로 작업할 때는 fetch함수를 실행해 프로미스가 처리되면 다시 .json을 호출해 이 프로미스가 처리될 때 까지 대기했어야 했다. 이와 달리 Axios에서는 axios.get으로 한번에 처리할 수 있다. get함수가 요청을 생성하고 json 구문 분석 후에 이 응답 객체에 우리를 대신해서 포함시키는 것이다.
const getStarWarsPerson = async (id) => {
try {
const res = await axios.get(`https://swapi.dev/api/people/${id}/`);
console.log(res);
} catch (e) {
console.log("ERROR!", e);
}
}
getStarWarsPerson(5);
refactoring
Axios로 헤더 세팅하기
위 사이트의 API를 사용하려면 Accept header를 지정해야 한다. 또한 json을 다시 얻기 위해서도 있다.
그렇지 않으면 디폴트 값의 HTML을 얻게 된다.
const getDadJoke = async () => {
const res = await axios.get("https://icanhazdadjoke.com/");
console.log(res);
}
getDadJoke();
위 코드의 요청으로 반환된 값을 보면 headers 특성이 있고, 살펴보면 text/html은 반환된 응답을 기반으로 Axios가 구성한 것이며, 반환된 실제 정보는 텍스트로 되어있고 Axios는 정보를 파싱하고 작동할 수 있는 객체로 변환할 것이다.
위 코드에서 요청할 때 application/json만을 원한다는 걸 확실히 해야한다.
이 API가 구성된 방식이다.
그냥 알 수 있는것이 아니고 위와같은 참고서를 읽고 이해해야 한다.
API 설정 방식은 JSON을 원하는 경우 헤더가 application/json으로 설정하도록 한다.
위 코드에서 axios.get으로 구성 정보와 함께 전달할 수 있는 두 번째 인수가 있고,
axios.get("https://icanhazdadjoke.com/", {});
구성할 수 있는 것 중 하나는 그 자체로 객체인 헤더이다.
axios.get("https://icanhazdadjoke.com/", { headers: {} });
이것을 독립적으로 만들거나 별개로 만들고 싶을 때
const getDadJoke = async () => {
const config = { headers: { Accept: 'application/json' } };
const res = await axios.get("https://icanhazdadjoke.com/", config);
console.log(res);
}
getDadJoke();
위 코드처럼 구현하면 된다.
console.log(res.data.joke);
// what is this movie ...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Click to get new jokes!</h1>
<button>Click me!</button>
<ul id="jokes">
</ul>
<script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
<script src="temp.js"></script>
</body>
</html>
const jokes = document.querySelector('#jokes');
const btn = document.querySelector('button');
const addNewJoke = async () => {
const jokeText = await getDadJoke();
const newLI = document.createElement('li');
newLI.append(jokeText.data.joke);
jokes.append(newLI);
}
const getDadJoke = async () => {
try {
const config = { headers: { Accept: 'application/json' } };
const res = await axios.get("https://icanhazdadjoke.com/", config);
return res;
}
catch (e) {
return "NO JOKES AVAILABLE!";
}
}
btn.addEventListener('click', addNewJoke);
TV 프로그램 검색 앱
const form = document.querySelector("#searchForm");
form.addEventListener("submit", async function(e) {
e.preventDefault();
const searchTerm = form.elements.query.value;
const res = await axios.get(`https://api.tvmaze.com/search/shows?q=${searchTerm}`);
makeImages(res.data);
form.elements.query.value = "";
})
const makeImages = (images) => {
for(let i of images) {
if(i.show.image){
const img = document.createElement('img');
img.src = i.show.image.medium;
document.body.append(img);
}
}
}
API에 따라 쿼리에 두 개 이상 넣는 경우가 있다. tvmaze api 같은 경우 미국 날짜, embed, 나라 명 등으로 검색이 가능하다. Axios가 제공하는 방법을 이용하여 쿼리 문자열이 없는 URL을 쓰고 매개변수인 params를 입력하는 객체를 추가해서 요청을 보낼 수 있다 (별도의 객체를 만들 수 있다).
참고로 form 태그를 사용한 이유는 input 이벤트나 change, keydown 이벤트보다 실시간 검색을 한다는 점에서 메리트가 있기 때문임.
다른 API를 사용할 때 API를 호출하거나 HTTP 요청하는 코드에 꼭 실수하기 마련이다. 천천히 신경써서 작성하려고 노력하고, API 과부하를 원하지 않는다면 문자마다 요청하지 말자. 예를 들어 사용자가 검색하기를 기다리기보다 직접 입력해서 요청을 보내기도 한다. 하지만 자신이 만든 API에 요청하거나 아니면 API가 과부하되지 않도록 약간의 지연이 있도록 한다.
const form = document.querySelector("#searchForm");
form.addEventListener("submit", async function(e) {
e.preventDefault();
const searchTerm = form.elements.query.value;
const config = {
params: {q: searchTerm, isFunny: 'colt'},
// headers: {} // 이런식으로 header를 추가할 수도 있다.
} // 여기에 작성하는 키-값이 쿼리 문자열에 나타날것임.
// url에 일일이 작성하려면 귀찮기 때문에 별도로 config 객체를 만들어서 url 뒤에 코드를 추가해준다.
// 객체를 이용해서 자동으로 추가하니 훨씬 간편할 때가 많다.
const res = await axios.get(`https://api.tvmaze.com/search/shows?q=${searchTerm}`, config);
makeImages(res.data);
form.elements.query.value = "";
})
const makeImages = (images) => {
for(let i of images) {
if(i.show.image){
const img = document.createElement('img');
img.src = i.show.image.medium;
document.body.append(img);
}
}
}
요청 URL에 내가 적은 쿼리 문자열 혹은 매개변수가 끝에 추가되어있는 것을 볼 수 있다.