fetch 함수 사용하기

Jayden ·2023년 3월 7일
0

자바스크립트는 HTTP Request 전송 기능을 제공하는 fetch API를 제공합니다.

기존 XMLHttpRequest와는 fetch API(fetch() 함수)는 Promise 방식으로 구현되어 있습니다.

따라서, Promise에 사용되는 catch(), error() 메서드를 통해, 에러처리를 구현할 수

있습니다.


HTTP 요청 방법은 method, 전송할 데이터는 body, 헤더 값은 headers에 정의합니다.

fetch API는 디폴트로 GET 방식으로 작동하고 GET 방식 사용시 method를

별도로 선언하지 않고, 데이터를 호출할 url만 입력하면 됩니다.

1. 요청 옵션

  1. 데이터 조회(GET)
fetch('https:// jsonplaceholder.typicode.com/post')
.then((response) => response.json())
.then((json)=> console.log(json))

fetch 함수를 호출하면 Promise 객체를 반환하는데, 이 객체는 HTTP 응답 전체를 나타냅니다.
우리가 필요한 데이터만을 가져오기(추출하기) 위해서 json() 메서드를 사용합니다.

  1. 데이터 생성(POST)
fetch('https://jsonplaceholder.typicode.com/posts',{
 method : 'POST',
 body : JSON.stringfy({
  title : 'foo'
  body : 'bar'
  userId : 1
}),
headers : {
 	'content-type' : 'application/json; charset=UTF-8'
}
}).then((response) => response.json())
.then((json) => console.log(json));
  1. 데이터 수정(PUT)
fetch('https://jsonplaceholder.typicode.com/posts/1,{
method : 'PUT',
body : JSON.stringfy({
      id : 1,
      title : 'foo',
      body : 'bar',
      userId : 1,
})
  headers : {
    'Content-type' : 'application/json; charse=UTF-8',
  }
  }).then((response)) => response.json())
  .then((json)) => console.log(json))
  1. 데이터 삭제
fetch('https://jsonplaceholder.typicode.com/posts/1',{
	method : 'DELETE'
});

2. 사용 예시

다음과 같이 토큰을 헤더에 담아서 해당 url로 fetch() 함수를 호출합니다.

fetch() 함수가 실행되고 정상적으로 이행이되면 then() 메소드에, 에러 발생시에는 catch()

메소드로 콘솔에 에러를 출력하도록 구현했습니다.

const fetchData = (e: React.FormEvent<HTMLFormElement>, url : string) => {

  e.preventDefault();

  const token = localStorage.getItem("amadeusAccessToken")

  
    const response = fetch(url,{   
        headers: {
          Authorization: `Bearer ${token}`
        }
      })
    })
    .then(res => res.json())
    .catch(e){
        console.log(e)
     }
  }

하지만 fetch() 함수는 상태코드가 4xx, 5xx 계열 에러가 발생하면, catch()로 넘어가지 않습니다.(4xx, 5xx 계열의 에러를 잡아내지 못합니다.)

따라서 상태코드가 200~299인지 체크하는 response.ok를 사용하여 에러처리를 진행할 수 있도록 하겠습니다.

const fetchData = (e: React.FormEvent<HTMLFormElement>, url : string) => {

  e.preventDefault();

  const token = localStorage.getItem("amadeusAccessToken")

    const response = fetch(url,{   
        headers: {
          Authorization: `Bearer ${token}`
        }
      })
    })
    .then(response => {
     	if(response.ok){
        	return response.json()  
        }
        else{
         throw new Error(`${response.status}`에러가 발생하였습니다.);
        }   
     )
    .catch(e){
        console.log(e)
     }
  ) 

위의 함수는 다음과 같이 async / await (에이싱크(O), 어씽크 아닙니다.ㅋㅋ) 키워드를 사용하여 구현 할 수 있습니다. 기능적으로는 위의 있는 then() / catch() 을 사용한 체이닝 방법과 동일하지만
체이닝이 길어질 경우에는 가독성 측면에서 훨신 좋습니다.

export const fetchData = async (e: React.FormEvent<HTMLFormElement>, url : string) => {

  e.preventDefault();

  const token = localStorage.getItem("amadeusAccessToken")

  try{
    	const response = await fetch(url,{   
        	headers: {
          		Authorization: `Bearer ${token}`
        	}
      	})
 
    	response.ok ? 
        return await response.json() :
 		throw new Error(`${response.status}`에러가 발생하였습니다.);      
    
  } catch(e){
              console.log(e);
     }
  }
}

3. 에러 발생 시 응답코드에 따른 로직 수행하기

위에서 에러가 발생할 경우 throw new Error('error message') 처럼 에러 객체에 메시지를 전달할 수 있지만, 에러코드 자체를 전달하지는 못합니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Error/Error
을 참고하면
new Error(message, fileName, lineNumber)로 정의되어 있어

에러 코드를 전달하려면 커스텀한 에러 객체를 정의해 주어야 합니다.

따라서 Error 클래스를 상속한 HTTPError 클래스를 정의하고, 상태코드를 멤버변수로 추가하도록 합니다.

에러 발생시 throw new HTTPError('상태 코드','에러 메시지') 형태로

catch( ) 메소드로 전달하도록 합니다.

export const fetchData = async (e: React.FormEvent<HTMLFormElement>, url : string) => {

  e.preventDefault();

  const token = localStorage.getItem("amadeusAccessToken")

  try{
    const response = await fetch(url,{   
        headers: {
          Authorization: `Bearer ${token}`
        }
      })
        if (response.ok) {
          return await response.json()
        } else {
          throw new HTTPError(response.status, response.statusText)
      }
    } catch(e){
        if(e instanceof HTTPError)
          switch(e.statusCode){
            case 401:
              setAmadeusAccessToken();
              break;
            default : 
              console.log(e);
        }
  }
}

class HTTPError extends Error {
  statusCode;
  constructor(statusCode: number, message?: string) {
    super(message)
    this.name = `HTTPError`
    this.statusCode = statusCode
  }
}
profile
J-SONE 프론트엔드 개발자

0개의 댓글