fetch

zimablue·2023년 8월 9일

javascript

목록 보기
21/30

서버에 네트워크 요청을 보내고 새로운 정보를 받아 promise 객체로 return 합니다.

fetch(resource, options)

return되는 객체는, API 호출이 성공했을 경우에는 response 객체를 resolve하고, 실패했을 경우 error 객체를 reject합니다.

fetch(resource, options)
  .then((response) => console.log(response))
  .catch((error) => console.log(error));

resource

취득하려는 리소스의 URL을 제공하는 문자열 또는 URL처럼 문자열 변환자를 포함한 객체.


options

요청에 적용하고자 하는 사용자 지정 설정을 포함하는 객체입니다. 사용 가능한 설정은 다음과 같습니다.

  • HTTP 방식(method) - 요청 메서드
  • HTTP 요청 헤더(headers) - 요청에 추가하고자 하는 헤더들
  • HTTP 요청 전문(body) - 요청에 추가하고자 하는 본문





GET

fetch() 는 디폴트로 GET 방식으로 작동하고 GET 방식은 요청 전문을 받지 않기 때문에 옵션 인자가 필요가 없습니다.

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => console.log(response)
);
// response

Response {
  body: ReadableStream
  bodyUsed: false
  headers: Headers {}
  ok: true
  redirected: false
  status: 200
  statusText: ""
  type: "cors"
  url: "https://jsonplaceholder.typicode.com/posts/1"
  [[Prototype]]: Response
}

대부분의 REST API들은 JSON 형태의 데이터를 응답하기 때문에, response 객체는 응답 본문을 JSON으로 파싱한 결과로 이행하는 프로미스를 반환하는 json()을 인스턴스 메서드로 제공합니다.

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json())
  .then((data) => console.log(data));
// data

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit↵suscipit recusandae consequuntur …strum rerum est autem sunt rem eveniet architecto"
}





POST

HTTP 방식(method): "POST", HTTP 요청 헤더(headers): JSON 포맷, HTTP 요청 전문(body): JSON 포맷으로 직렬화한 데이터 생성 요청합니다.

fetch("https://jsonplaceholder.typicode.com/posts", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    title: "Test",
    body: "I am testing!",
    userId: 1,
  }),
}).then((response) => console.log(response));
// response

Response {}
body: ReadableStream
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 201
statusText: ""
type: "cors"
url: "https://jsonplaceholder.typicode.com/posts"
[[Prototype]]: Response





DELETE

DELETE 방식에서는 보낼 데이터가 없기 때문에, HTTP 요청 헤더(headers)와 HTTP 요청 전문(body) 옵션이 필요가 없습니다.

fetch("https://jsonplaceholder.typicode.com/posts/1", {
  method: "DELETE",
})
  .then((response) => response.json())
  .then((data) => console.log(data));
// data

{}





예시 코드

JSON.parse()와 response.json()의 차이

JSON.parse()에는 response의 body만 받을 수 있습니다.
response.json() 메서드에서는 응답 header, body를 포함한 response 객체 자체를 받아서 body만 읽으며 Promise 객체를 반환합니다.


<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Http</title>
    <link rel="stylesheet" href="assets/styles/app.css" />
    <script src="assets/scripts/app.js" defer></script>
  </head>
  <body>
    <!-- 데이터 생성시 사용할 탬플릿 -->
    <template id="single-post">
      <li class="post-item">
        <h2></h2>
        <p></p>
        <button>DELETE</button>
      </li>
    </template>
    <section id="new-post">
      <!-- 데이터 생성시 데이터 입력 폼 -->
      <form>
        <div class="form-control">
          <label for="title">Title</label>
          <input type="text" id="title" />
        </div>
        <div class="form-control">
          <label for="content">Content</label>
          <textarea rows="3" id="content"></textarea>
        </div>
        <button type="submit">ADD</button>
      </form>
    </section>
    <section id="available-posts">
      <button>FETCH POSTS</button>
      <!-- 응답 받은 데이터를 보여줄 리스트 -->
      <ul class="posts"></ul>
    </section>
  </body>
</html>
// app.js

const listElement = document.querySelector(".posts");
const postTemplate = document.getElementById("single-post");
const form = document.querySelector("#new-post form");
const fetchButton = document.querySelector("#available-posts button");
const postList = document.querySelector("ul");

function sendHttpRequest(method, url, data) {
  //promise 객체를 return
  return fetch(url, {
    method: method,
    body: JSON.stringify(data),
    headers: {
      "Content-Type": "application/json",
    },
  })
    .then((response) => {
      if (response.status >= 200 && response.status < 300) {
        // fetch는 파싱된 응답이 아닌 스트리밍된 응답을 반환하기 때문에 .json()을 사용하여 프로미스로 반환
        // fetch의 응답은 header가 도착하자마자 주어지며 body가 없기 때문에 pending 상태의 프로미스
        // .json()은 JSON.parse()대신 사용하며 스트림이 완료될 때까지 기다린 후에 body의 텍스트를 프로미스로 반환
        return response.json();
      } else {
        // 서버와의 오류로 인한 에러일 경우
        return response.json().then((errData) => {
          console.log(errData);
          throw new Error("Something went wrong - server-side");
        });
      }
    })
    .catch((error) => {
      // 네트워크 에러일 경우
      console.log(error);
      throw new Error("Something went wrong");
    });
}


// 데이터 요청
async function fetchPosts() {
  try {
    const responseData = await sendHttpRequest(
      "GET",
      "https://jsonplaceholder.typicode.com/posts"
    );
    const listOfPosts = responseData;
    for (const post of listOfPosts) {
      const postEl = document.importNode(postTemplate.content, true);
      postEl.querySelector("h2").textContent = post.title.toUpperCase();
      postEl.querySelector("p").textContent = post.body;
      postEl.querySelector("li").id = post.id;
      listElement.append(postEl);
    }
  } catch (error) {
    alert(error.message);
  }
}

fetchButton.addEventListener("click", fetchPosts);

// 데이터 생성
async function createPost(title, content) {
  const userId = Math.random();
  const post = {
    title: title,
    body: content,
    userId: userId,
  };
  sendHttpRequest("POST", "https://jsonplaceholder.typicode.com/posts", post);
}

form.addEventListener("submit", (event) => {
  event.preventDefault();
  const enteredTitle = event.currentTarget.querySelector("#title").value;
  const enteredContent = event.currentTarget.querySelector("#content").value;
  createPost(enteredTitle, enteredContent);
});


// 데이터 삭제
postList.addEventListener("click", (event) => {
  if (event.target.tagName === "BUTTON") {
    const postId = event.target.closest("li").id;
    sendHttpRequest(
      "DELETE",
      `https://jsonplaceholder.typicode.com/posts/${postId}`
    );
  }
});





Dale님의 fetch 모듈화

async function post(host, path, body, headers = {}) {
  const url = `https://${host}/${path}`;
  const options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...headers,
    },
    body: JSON.stringify(body),
  };
  const res = await fetch(url, options);
  const data = await res.json();
  if (res.ok) {
    return data;
  } else {
    throw Error(data);
  }
}

post("jsonplaceholder.typicode.com", "posts", {
  title: "Test",
  body: "I am testing!",
  userId: 1,
})
  .then((data) => console.log(data))
  .catch((error) => console.log(error));





참고

자바스크립트의 fetch() 함수로 원격 API 호출하기

0개의 댓글