Axios
(1) Axios란?
공식문서에 따르면 axios 란 node.js와 브라우저를 위한 Promise 기반 http 클라이언트 라고 소개하고 있습니다. 다시 말해 http를 이용해서 서버와 통신하기 위해 사용하는 패키지라고 생각하시면 됩니다.
(2) Axios 설치하기
yarn add axios
(3) 테스트를 하기 위해 목업데이터를 db.json설정
{
"todos": [
{
"id": "1",
"title": "react"
}
]
}
Axios 문법 구성
axios({
url: 'https://test/api/cafe/list/today', // 통신할 웹문서
method: 'get', // 통신할 방식
data: { // 인자로 보낼 데이터
foo: 'diary'
}
});
Axios 요청(request) 파라미터 옵션
요청 Config | Axios Docs
요청 Config 다음은 요청을 만드는 데 사용할 수 있는 config 옵션들 입니다. 오직 url만 필수입니다. method를 지정하지 않으면 GET방식이 기본값 입니다. { url: '/user', method: 'get', baseURL: 'https://some-domain.
axios-http.com
붉은색이 자주 사용하는 파라미터 옵션이고, 나머지는 참고로 한번씩만 보고 넘어가자.
- method : 요청방식. (get이 디폴트)
- url : 서버 주소
- baseURL : url을 상대경로로 쓸대 url 맨 앞에 붙는 주소.
- 예를들어, url이 /post 이고 baseURL이 https://some-domain.com/api/ 이면,
https://some-domain.com/api/post로 요청 가게 된다.
- 예를들어, url이 /post 이고 baseURL이 https://some-domain.com/api/ 이면,
- headers : 요청 헤더
- data : 요청 방식이 'PUT', 'POST', 'PATCH' 해당하는 경우 body에 보내는 데이터
- params : URL 파라미터 ( ?key=value 로 요청하는 url get방식을 객체로 표현한 것)
- timeout : 요청 timeout이 발동 되기 전 milliseconds의 시간을 요청. timeout 보다 요청이 길어진다면, 요청은 취소되게 된다.
- responseType : 서버가 응답해주는 데이터의 타입 지정 (arraybuffer, documetn, json, text, stream, blob)
- responseEncoding : 디코딩 응답에 사용하기 위한 인코딩 (utf-8)
- transformRequest : 서버에 전달되기 전에 요청 데이터를 바꿀 수 있다.
- 요청 방식 'PUT', 'POST', 'PATCH', 'DELETE' 에 해당하는 경우에 이용 가능
- 배열의 마지막 함수는 string 또는 Buffer, 또는 ArrayBuffer를 반환합
- header 객체를 수정 가능
- 요청 방식 'PUT', 'POST', 'PATCH', 'DELETE' 에 해당하는 경우에 이용 가능
- transformResponse : 응답 데이터가 만들어지기 전에 변환 가능
- withCredentials : cross-site access-control 요청을 허용 유무. 이를 true로 하면 cross-origin으로 쿠키값을 전달 할 수 있다.
- auth : HTTP의 기본 인증에 사용. auth를 통해서 HTTP의 기본 인증이 구성이 가능
- maxContentLength: http 응답 내용의 max 사이즈를 지정하도록 하는 옵션
- validateStatus : HTTP응답 상태 코드에 대해 promise의 반환 값이 resolve 또는 reject 할지 지정하도록 하는 옵션
- maxRedirects : node.js에서 사용되는 리다이렉트 최대치를 지정
- httpAgent / httpsAgent : node.js에서 http나 https를 요청을 할때 사용자 정의 agent를 정의하는 옵션
- proxy : proxy서버의 hostname과 port를 정의하는 옵션
- cancelToken : 요청을 취소하는데 사용되어 지는 취소토큰을 명시
/* axios 파라미터 문법 예시 */
axios({
method: "get", // 통신 방식
url: "www.naver.com", // 서버
headers: {'X-Requested-With': 'XMLHttpRequest'} // 요청 헤더 설정
params: { api_key: "1234", langualge: "en" }, // ?파라미터를 전달
responseType: 'json', // default
maxContentLength: 2000, // http 응답 내용의 max 사이즈
validateStatus: function (status) {
return status >= 200 && status < 300; // default
}, // HTTP응답 상태 코드에 대해 promise의 반환 값이 resolve 또는 reject 할지 지정
proxy: {
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
}, // proxy서버의 hostname과 port를 정의
maxRedirects: 5, // node.js에서 사용되는 리다이렉트 최대치를 지정
httpsAgent: new https.Agent({ keepAlive: true }), // node.js에서 https를 요청을 할때 사용자 정의 agent를 정의
})
.then(function (response) {
// response Action
});
Axios 응답(response) 데이터
axios를 통해 요청을 서버에게 보내면, 서버에서 처리를하고 다시 데이터를 클라이언트에 응답 하게 된다.
이를 .then으로 함수인자로(response)로 받아 객체에 담진 데이터가 바로 응답 데이터이다.
ajax를 통해 서버로부터 받는 응답의 정보는 다음과 같다.
axios({
method: "get", // 통신 방식
url: "www.naver.com", // 서버
})
.then(function(response) {
console.log(response.data)
console.log(response.status)
console.log(response.statusText)
console.log(response.headers)
console.log(response.config)
})
response.data: {}, // 서버가 제공한 응답(데이터)
response.status: 200, // `status`는 서버 응답의 HTTP 상태 코드
response.statusText: 'OK', // `statusText`는 서버 응답으로 부터의 HTTP 상태 메시지
response.headers: {}, // `headers` 서버가 응답 한 헤더는 모든 헤더 이름이 소문자로 제공
response.config: {}, // `config`는 요청에 대해 `axios`에 설정된 구성(config)
response.request: {}
// `request`는 응답을 생성한 요청
// 브라우저: XMLHttpRequest 인스턴스
// Node.js: ClientRequest 인스턴스(리디렉션)
Axios 단축문법
axios를 편리하게 사용하기 위해 모든 요청 메소드는 aliases가 제공된다.
위 처럼 객체 옵션을 이것저것 주면 가독성이 떨어지고 너저분하니, 함수형으로 재구성하여 나눠논 것으로 이해하면 된다.
axios의 Request method에는 대표적으로 다음과 같은 것들이 있다.
- GET : axios.get(url[, config])
- POST : axios.post(url, data[, config])
- PUT : axios.put(url, data[, config])
- DELETE : axios.delete(url[, config])
Axios GET
(1) Axios GET
get은 서버의 데이터를 조회할 때 사용합니다. 기본적인 사용방법은 아래와 같습니다.
axios.get(url[, config]) // GET
url에는 서버의 url이 들어가고, config에는 기타 여러가지 설정을 추가할 수 있습니다.
config는 axios 공식문서에서 확인하세요.
(2) 우리가 사용하는 json-server API 명세서 확인하기 [중요 🔥]
우리가 Axios를 사용해서 GET 요청 코드를 작성하기에 앞서, 어떤 방식으로 요청 해야할지는 우리가 사용하는 json-server의 방식을 알아보아야 합니다.
다시 말해, Axios는 GET 요청을 할 수 있도록 도와주는 패키지일뿐이지, “어떻게 요청을 해야하지?” 와 같은 방식에 대한 확인은 우리가 사용할 API 명세서를 보아야 한다는 뜻 입니다. 예를 들어 GET 요청을 할 때 path variable로 해야할지, query로 보내야할지는 API를 만든 사람이 하라는대로 해야 하기 때문이죠.
json-server의 공식문서를 보면, 전체 정보나 상세 정보는 아래와 같이 path variable 로 url을 작성하면 되네요.
그리고 filter와 같은 기능을 위해서 GET 요청을 하고자할 때는 query로 보내라고 명시하고 있습니다.
(3) 코드로 알아보기
좀 더 실용적인 예시를 코드를 통해 사용방법을 알아봅니다. 우리가 만든 json-server에 있는 todos를 axios를 이용해서 fetching하고 useState를 통해서 관리하는 로직입니다. 새로운 프로젝트를 만들어서 코드를 작성해보세요.
// src/App.js
import React, { useEffect, useState } from "react";
import axios from "axios"; // axios import 합니다.
const App = () => {
const [todos, setTodos] = useState(null);
// axios를 통해서 get 요청을 하는 함수를 생성합니다.
// 비동기처리를 해야하므로 async/await 구문을 통해서 처리합니다.
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data); // 서버로부터 fetching한 데이터를 useState의 state로 set 합니다.
};
// 생성한 함수를 컴포넌트가 mount 됐을 떄 실행하기 위해 useEffect를 사용합니다.
useEffect(() => {
// effect 구문에 생성한 함수를 넣어 실행합니다.
fetchTodos();
}, []);
// data fetching이 정상적으로 되었는지 콘솔을 통해 확인합니다.
console.log(todos); // App.js:16
return <div>App</div>;
};
export default App;
const fetchTodos = async () => {
const {data} = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
console.log(todos);
data를 중괄호로 감싼 이유는 구조분해할당해주기 위함이다.
const fetchTodos = async () => {
const data = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
console.log(todos);
data를 구조분해할당해주지않는다면 아래와같은 log가 찍히게 된다.
// localhos:3000
콘솔로 결과를 확인하니, 우리가 생성한 Todos를 정상적으로 서버에서 가져와서 state가 set 한 것을 확인할 수 있습니다.
Axios POST
(1) Axios POST
axios.post(url[, data[, config]]) // POST
post는 보통 서버에 데이터를 추가할 때 사용합니다. 다만 post 요청에 대한 로직은 BE 개발자가 구현하는 것이기때문에 추가외에 다른 용도로 사용될 수 있지만, 보통은 클라이언트의 데이터를 body형태로 서버에 보내고자 할 때 사용합니다. 아래 코드를 작성하기에 앞서, GET 에서 본 것과 같이 json-server의 POST 요청 방식을 확인하고 오시길 바랍니다.
(2) 코드로 알아보기
GET 코드예시에서 POST 코드가 추가됩니다.
아래 코드를 설명합니다.
- 화면에 인풋과 버튼이 있고, 인풋에 어떤 값을 넣고 버튼을 클릭했을 때 onSubmitHandler 이 실행됩니다.
- onSubmitHandler 함수의 목적은 todo를 body에 담아 서버로 POST 요청을 보내는 것 입니다.
// src/App.jsx
import React, { useEffect, useState } from "react";
import axios from "axios"; // axios import 합니다.
const App = () => {
// 새롭게 생성하는 todo를 관리하는 state
const [todo, setTodo] = useState({
title: "",
});
const [todos, setTodos] = useState(null);
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
const onSubmitHandler = async (todo) => {
//1. 이때 todos는 [{투두하나}]임
await axios.post("http://localhost:3001/todos", todo); // 이때 서버에 있는 todos도 [{투두하나}]임
// 근데 여기서 서버 요청이 끝나고 서버는 [{투두가},{두개임}]
setTodos([...todos, todo]); //2. <-- 만약 이게 없다면, go to useEffect
//4. 새로고침해서 진짜 현재 서버 데이터를 받아오기전에 상태를 똑같이 동기시켜줌
//5. 어떻게보면 유저한테 서버에서 새로 받아온것처럼 속이는거지
};
useEffect(() => {
fetchTodos(); //3. 새로고침해서 여기를 다시 실행해줘야 서버값이 새로 들어옴 e.g) [{투두가},{두개임}]
}, []);
return (
<>
<form
onSubmit={(e) => {
// 👇 submit했을 때 브라우저의 새로고침을 방지합니다.
e.preventDefault();
onSubmitHandler(todo);
}}
>
<input
type="text"
onChange={(ev) => {
const { value } = ev.target;
setTodo({
...todo,
title: value,
});
}}
/>
<button>추가하기</button>
</form>
<div>
{todos?.map((todo) => (
<div key={todo.id}>{todo.title}</div>
))}
</div>
</>
);
};
export default App;
POST 요청을 성공적으로 마쳤으면, 브라우저를 새로고침해보세요. 우리가 새롭게 추가한 Todo가 화면에 보일 것 입니다. 새로고침을 해야만 새로운 정보가 표시되는 이유가 뭘까요? 어떻게 해야 새로고침 없이 화면이 업데이트 될지 고민해보세요. 여러분들은 이미 구현해본 경험이 있습니다.
(3) 네트워크탭 확인하기 [중요 🔥]
우리가 post 요청을 보냈을 때, 브라우저의 네트워크 탭에는 어떤 로그가 생기는지 확인해봅니다. 네트워크 쪽 개발을 할 때는 항상 브라우저에 있는 네트워크 탭을 확인하면서 개발을 진행해야 합니다. 어떤 문제가 생겼을 때 이정보를 통해 디버깅을 할 수 있기 때문입니다.
headers
- Request URL을 통해서 우리가 의도한 URL로 post 요청을 보냈음을 알 수 있습니다.
- Request Method를 통해서 우리가 POST 메서드를 사용했음을 알 수 있습니다.
- Status Code를 통해서 201 코드를 받았고, 정상적으로 네트워크가 이루어졌음을 알 수 있습니다. status code는 자동으로 생성되는 것이 아니라 BE개발자가 직접 개발을 하고 설정한 code가 브라우저에게 보이게 됩니다. 그래서 만약 BE개발자가 구현을 해놓지 않았다면 문맥과 다른 status code가 브라우저에 보일 수 있습니다.
- 그 밖에도 request headers와 response headers 정보가 추가적으로 있습니다. 이 부분은 각 항목들이 어떤 것을 우리게 보여주는지 더 알아보시길 바랍니다.
payload
- payload에서는 우리가 보낸 body를 확인 할 수 있습니다. 우리가 보낸 값이 정상적으로 보입니다.
response
- response에서는 우리가 보낸 post에 요청에 대한 서버의 응답값을 확인할 수 있습니다. 이 Response 값은 자동으로 생성되는 것이 아니라, FE 개발자가 BE 개발자에게 요청한 것을 직접 개발을 해야 생기는 값입니다. 우리가 사용한 json-server의 경우 POST 요청을 했을 때, 클라이언트가 보낸 body를 그대로 응답해주도록 만들어져 패키지이기 때문에 위와 같이 표시됩니다.
Axios DELETE
(1) Axios delete
DELETE는 저장되어 있는 데이터를 삭제하고자 요청을 보낼 때 사용합니다.
axios.delete(url[, config]) // DELETE
(2) 코드로 알아보기
GET, POST 와 함께 코드가 작성됩니다. onClickDeleteButtonHandler 와 map 을 돌린 항목별로 삭제하기 버튼을 추가해줍니다. 새롭게 추가한 코드는 노란색으로 마킹한 부분입니다.
// src/App.jsx
import React, { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todo, setTodo] = useState({
title: "",
});
const [todos, setTodos] = useState(null);
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
const onSubmitHandler = (todo) => {
axios.post("http://localhost:3001/todos", todo);
};
// 새롭게 추가한 삭제 버튼 이벤트 핸들러
const onClickDeleteButtonHandler = (todoId) => {
axios.delete(`http://localhost:3001/todos/${todoId}`);
};
useEffect(() => {
fetchTodos();
}, []);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
<input
type="text"
onChange={(ev) => {
const { value } = ev.target;
setTodo({
...todo,
title: value,
});
}}
/>
<button>추가하기</button>
</form>
<div>
{todos?.map((todo) => (
<div key={todo.id}>
{todo.title}
{/* 디자인이 요상하긴 하지만..! 삭제 버튼 추가 */}
<button
type="button"
onClick={() => onClickDeleteButtonHandler(todo.id)}
>
삭제하기
</button>
</div>
))}
</div>
</>
);
};
export default App;
DELETE 요청이 성공적으로 이루어졌다면, 브라우저를 새로고침 했을 때 삭제한 Todo가 화면에서 보이지 않는 것을 알 수 있습니다.
(3) 네트워크 탭 확인하기
POST 에서 확인한 것과 같이 DELETE 요청에서도 어떤 로그가 보이는지 네트워크탭을 확인해보세요.
Axios PATCH
(1) Axios patch
patch는 보통 어떤 데이터를 수정하고자 서버에 요청을 보낼 때 사용하는 메서드 입니다. 다만, 이것은 http 환경에서 서로가 한 약속이자 문맥이기때문에, 수정을 하고자 반드시 patch, put 을 써야만 하는 것은 아닙니다. BE에 의해서 POST를 통해서 “수정" 이라는 기능은 충분히 만들 수 있기 때문이죠. 다만 이러한 약속들을 대부분의 개발자들이 지키고 있다는 점을 알려드리고 싶습니다.
axios.patch(url[, data[, config]]) // PATCH
(2) 코드로 알아보기
GET, POST, DELETE 예제에 코드가 추가됩니다. put은 patch와 동일한 원리이기때문에 생략합니다.
Todo를 수정하기 위해 필요한 데이터는 2개가 있습니다. 수정하고자하는 Todo의 id, 그리고 수정하고자 하는 값입니다. 수정하고자 하는 값은 기존에 있던 todo라는 state를 사용하면 될 것이고, id는 직접 입력을 해서 url로 넘겨주는 방식으로 구현하겠습니다.
보통은 수정기능을 만들 때 직접 id를 입력받아 처리는 방식은 거의 없습니다. 다만, 이번 예시에서는 아주 간단한 코드로 기능을 구현하는 것이기때문에 위와 같이 처리하겠습니다. 새롭게 추가된 코드는 노란색으로 마킹한 부분입니다.
// src/App.jsx
import React, { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todo, setTodo] = useState({
title: "",
});
const [todos, setTodos] = useState(null);
// patch에서 사용할 id, 수정값의 state를 추가
const [targetId, setTargetId] = useState(null);
const [editTodo, setEditTodo] = useState({
title: "",
});
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
const onSubmitHandler = (todo) => {
axios.post("http://localhost:3001/todos", todo);
};
const onClickDeleteButtonHandler = (todoId) => {
axios.delete(`http://localhost:3001/todos/${todoId}`);
};
// 수정버튼 이벤트 핸들러 추가 👇
const onClickEditButtonHandler = (todoId, edit) => {
axios.patch(`http://localhost:3001/todos/${todoId}`, edit);
};
useEffect(() => {
fetchTodos();
}, []);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
{/* 👇 수정기능에 필요한 id, 수정값 input2개와 수정하기 버튼을 추가 */}
<div>
<input
type="text"
placeholder="수정하고싶은 Todo ID"
onChange={(ev) => {
setTargetId(ev.target.value);
}}
/>
<input
type="text"
placeholder="수정값 입력"
onChange={(ev) => {
setEditTodo({
...editTodo,
title: ev.target.value,
});
}}
/>
<button
// type='button' 을 추가해야 form의 영향에서 벗어남
type="button"
onClick={() => onClickEditButtonHandler(targetId, editTodo)}
>
수정하기
</button>
</div>
<input
type="text"
onChange={(ev) => {
const { value } = ev.target;
setTodo({
...todo,
title: value,
});
}}
/>
<button>추가하기</button>
</form>
<div>
{todos?.map((todo) => (
<div key={todo.id}>
{/* todo의 아이디를 화면에 표시 */}
{todo.id} :{todo.title}
<button
type="button"
onClick={() => onClickDeleteButtonHandler(todo.id)}
>
삭제하기
</button>
</div>
))}
</div>
</>
);
};
export default App;
(3) 네트워크 탭 확인하기
POST 에서 확인한 것과 같이 PATCH 요청에서도 어떤 로그가 보이는지 네트워크탭을 확인해보세요.
.env
.env 란 무엇이고 왜 사용하며 어떻게 사용해야할까? 아래 내용음 참고하여 .env 이용해서 우리가 사용할 API 서버의 IP 또는 URL을 숨겨서 처리해봅시다.
[React] .env (환경변수 관리)
※대학생이 공부하면서 작성한 글입니다※ ※이 글은 CRA로 만들었을 시 기준입니다※ env env는 API key, port, DB 등 민감한 정보를 환경변수에 담아 관리하는 방법이다. 🛑 env 주의사항 🔴 root 폴더
tooo1.tistory.com
최종정리
- Axios를 이용해서 API 서버와 통신할 수 있다.
- Axios는 http 통신을 도와주는 패키지이며, 구체적인 명세는 API 명세서를 확인해야 한다.
- 브라우저 네트워크 탭을 잘 봐야 한다.
- http method, staus code와 같은 정보들은 BE개발자가 구현해주는 부분이며, 약속이자 문맥이므로 BE와 FE간의 커뮤니케이션이 잘 되어야 한다.
- 네트워크 통신 이후, 화면을 업데이트 하고자 한다면 별도로 FE에서 추가로 구현해야 한다.
'내일배움캠프[4기_Reac트랙] > [원격]React_심화' 카테고리의 다른 글
성능최적화[심화_6] (0) | 2023.01.08 |
---|---|
Thunk(2)[심화_5] (0) | 2023.01.06 |
Thunk(1)[심화_4] (0) | 2023.01.06 |
json-server[심화_2] (0) | 2022.12.22 |
ReduxToolkit_[심화_1] (0) | 2022.12.22 |