본문 바로가기

카테고리 없음

Study_240611 (json-server , axios)

json-server 공식 페이지 ( 이용 시 유용한 정보 많으니 참고 많이 할 것 )

https://www.npmjs.com/package/json-server

 

json-server

[![Node.js CI](https://github.com/typicode/json-server/actions/workflows/node.js.yml/badge.svg)](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**보다 코드가 더 깔끔해질 수 있음