json-server 공식 페이지 ( 이용 시 유용한 정보 많으니 참고 많이 할 것 )
https://www.npmjs.com/package/json-server
json-server
[](https://github.com/typicode/json-server/actions/workflows/node.js.yml). Latest version: 1.0.0-beta.1, last published: 6 days ago. Start using json-server in yo
www.npmjs.com
json-server란, 아주 간단한 DB와 API서버를 생성해주는 패키지
=> FE가 BE작업을 기다리지 않고 FE의 로직과 화면을 구현 하는 효율적인 협업 방법.
yarn add json-server
or
yarn add json-server -D # 개발 환경인 경우, -D 옵션을 함께 입력
루트 경로에 db.json 생성
실행 시 -> yarn json-server db.json --port 4000 ( 4000은 예시 )
{
"todos": [
{
"id": 1,
"title": "json-server",
"content": "json-server배우기"
}
]
}
localhost:4000/todos 주소창에 입력 시 아래처럼 확인 가능
Axios
node.js와 브라우저를 위한 Promise 기반 http 클라이언트 -> http를 이용하여 서버와 통신하기 위해 사용하는 패키지
fetch VS axios로도 비교하므로 fetch의 일종으로 이해해도됨
설치
yarn add axios
axios는 아래와 같은 과정이 필요없음
const data = await response.json();
따라서 아래와 같이 작성 가능
import { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [post, setPost] = useState(null);
useEffect(() => {
const fetchPost = async () => {
try {
const data = await axios(
);
setPost(data);
} catch (error) {
console.log("Error", error);
}
};
fetchPost();
}, []);
console.log(post);
return <>{post ? <div>{post.title}</div> : <div>Loading...</div>}</>;
};
export default App;
아래는 완성된 get 코드
import { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todos, settodos] = useState(null);
useEffect(() => {
const fetchPost = async () => {
try {
// 구조 분해 할당으로 get 내부의 data 접근
const { data } = await axios.get("http://localhost:4000/todos");
settodos(data);
} catch (error) {
console.log("Error", error);
}
};
fetchPost();
}, []);
console.log("todos => ", todos);
return <></>;
};
export default App;
아래는 완성된 POST 코드
import { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todos, setTodos] = useState(null);
const [todo, setTodo] = useState({
title: "",
});
const onSubmitHandler = async (todo) => {
await axios.post("http://localhost:4000/todos", todo);
};
// 만일 fetch를 사용했다면, 이렇게 JSON.stringify를 '직접' 해줘야 함
// await fetch("http://localhost:4000/todos", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(todo),
// });
useEffect(() => {
const fetchPost = async () => {
try {
// 구조 분해 할당으로 get 내부의 data 접근
const { data } = await axios.get("http://localhost:4000/todos");
setTodos(data);
} catch (error) {
console.log("Error", error);
}
};
fetchPost();
}, []);
console.log(todos);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
<input
type="text"
onChange={(e) => {
setTodo({ ...todo, title: e.target.value });
}}
/>
<button type="submit">추가하기</button>
</form>
</>
);
};
export default App;
POST 시 db.json에도 자동으로 반영됨
{
"todos": [
{
"id": 1,
"title": "json-server"
},
{
"id": "a339",
"title": "abc"
},
{
"id": "4c16",
"title": "123"
}
]
}
json-server에서는 요청 시 id를 포함하여 응답하고 DB에 저장 될 때는 자동으로 저장됨
아래는 완성된 DELETE 코드
import { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todos, setTodos] = useState(null);
const [todo, setTodo] = useState({
title: "",
});
const onSubmitHandler = async (todo) => {
const { data } = await axios.post("http://localhost:4000/todos", todo);
//끝나고 나면 -> await는 반드시 처리가 끝나기를 기다리고 실행
setTodos([...todos, data]);
};
// 만일 fetch를 사용했다면, 이렇게 JSON.stringify를 '직접' 해줘야 함
// await fetch("http://localhost:4000/todos", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(todo),
// });
const onDeleteHandler = async (id) => {
await axios.delete("http://localhost:4000/todos/" + id);
setTodos(todos.filter((todo) => todo.id !== id));
};
useEffect(() => {
const fetchPost = async () => {
try {
// 구조 분해 할당으로 get 내부의 data 접근
const { data } = await axios.get("http://localhost:4000/todos");
setTodos(data);
} catch (error) {
console.log("Error", error);
}
};
fetchPost();
}, []);
console.log(todos);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
<input
type="text"
onChange={(e) => {
setTodo({ ...todo, title: e.target.value });
}}
/>
<button type="submit">추가하기</button>
</form>
{/* 옵셔널 체이닝 -> null or undefined일 경우 undefined 리턴
null은 map 메서드가 없음으로 오류 발생 */}
{todos?.map((todo) => {
return (
<div key={todo.id}>
<span>{todo.title}</span>
<button
onClick={() => {
onDeleteHandler(todo.id);
}}
>
삭제
</button>
</div>
);
})}
</>
);
};
export default App;
삭제 시에는 id를 보내는 것을 확인함
아래는 완성된 PATCH 코드
import { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todos, setTodos] = useState(null);
const [todo, setTodo] = useState({
title: "",
});
const [targetId, setTargetId] = useState("");
const [editTodo, setEditTodo] = useState({
title: "",
});
const onSubmitHandler = async (todo) => {
const { data } = await axios.post("http://localhost:4000/todos", todo);
//끝나고 나면 -> await는 반드시 처리가 끝나기를 기다리고 실행
setTodos([...todos, data]);
};
// 만일 fetch를 사용했다면, 이렇게 JSON.stringify를 '직접' 해줘야 함
// await fetch("http://localhost:4000/todos", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(todo),
// });
const onDeleteHandler = async (id) => {
await axios.delete("http://localhost:4000/todos/" + id);
setTodos(todos.filter((todo) => todo.id !== id));
};
const onEditHandler = async (targetId, editTodo) => {
await axios.patch("http://localhost:4000/todos/" + targetId, editTodo);
const newTodos = todos.map((todo) => {
if (todo.id === targetId) {
return {
...todo,
title: editTodo.title,
};
}
return todo;
});
setTodos(newTodos);
};
useEffect(() => {
const fetchPost = async () => {
try {
// 구조 분해 할당으로 get 내부의 data 접근
const { data } = await axios.get("http://localhost:4000/todos");
setTodos(data);
} catch (error) {
console.log("Error", error);
}
};
fetchPost();
}, []);
console.log(todos);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
<div>
<input
type="text"
placeholder="수정하고싶은 Todo Id를 입력"
onChange={(e) => {
setTargetId(e.target.value);
}}
/>
<input
type="text"
placeholder="수정할 값 입력"
onChange={(e) => {
setEditTodo({ ...editTodo, title: e.target.value });
}}
/>
<button
type="button"
onClick={() => {
onEditHandler(targetId, editTodo);
}}
>
수정하기
</button>
</div>
<input
type="text"
onChange={(e) => {
setTodo({ ...todo, title: e.target.value });
}}
/>
<button type="submit">추가하기</button>
</form>
{/* 옵셔널 체이닝 -> null or undefined일 경우 undefined 리턴
null은 map 메서드가 없음으로 오류 발생 */}
{todos?.map((todo) => {
return (
<div key={todo.id}>
<span>{todo.title}</span>
<button
onClick={() => {
onDeleteHandler(todo.id);
}}
>
삭제
</button>
</div>
);
})}
</>
);
};
export default App;
axios의 장점
- 기본 설정 및 인터셉터 지원
- 기본 설정: **axios**는 기본 설정을 정의하고, 이를 통해 모든 요청에 공통 설정을 적용
- 인터셉터: 요청 또는 응답을 가로채서 전처리 또는 후처리할 수 있습니다. 이를 통해 인증 토큰을 자동으로 추가하거나 오류를 일괄 처리
- 더 나은 오류 처리
- 에러 핸들링: **axios**는 HTTP 상태 코드를 기준으로 한 일관된 오류 처리를 제공 **fetch**는 기본적으로 네트워크 오류만 catch 블록으로 전달되고, 4xx, 5xx 오류는 then 블록에서 처리
-
- 브라우저 호환성
- 구형 브라우저 지원: **axios**는 구형 브라우저와의 호환성이 좋음 **fetch**는 구형 브라우저에서 지원되지 않을 수 있어 폴리필이 필요
- 간단한 사용법
- 간결한 문법: **axios**는 간결하고 직관적인 문법을 제공하여 사용하기 쉬움 **fetch**보다 코드가 더 깔끔해질 수 있음