타입스크립트 올인원 : Part2 - 세션2

안지환·2023년 12월 3일
0

강의

목록 보기
3/10
post-custom-banner

⭐️ Overview

Axios 다양한 방식으로 사용

Axios는 브라우저 및 node.js용 프로미스 기반 HTTP 클라이언트로 요청을 보내는 라이브러리 입니다.

Node 18 버전 이후에 fetch를 통해서 HTTP 클라이언트 요청을 받는 기능이 내장되어 있습니다. 그렇지만 Axios에는 기본적으로 Promise 비동기가 처리되어 있어 아직은 이 라이브러리를 사용하는 것을 선호하고 있습니다.

Axios 라이브러리는 NPM 패키지 매니저에서 다운을 받을 수 있습니다.

npm install axios

Axios는 TS 타입 지원이 되는 라이브러리 입니다. 타입 지원 여부에 대한 자세한 내용은 타입스크립트 올인원 : Part2 - 세션0에 참고하면 되겠습니다.

Axios의 내부 구조에 대해서 알아보겠습니다.

(async () => {
  try {
    const req = await axios.get('https://fakestoreapi.com/products/1')
    console.log(req.data);

  } catch (error) {
    console.log(error)
  }

})();

axios는 get 요청을 통해서 외부 API를 요청합니다.
get 요청 주소에 JSON 데이터를 가져옵니다.

Axios 내부 인터페이스는 다음과 같습니다.

export interface AxiosStatic extends AxiosInstance {
  create(config?: CreateAxiosDefaults): AxiosInstance;
  Cancel: CancelStatic;
  CancelToken: CancelTokenStatic;
  Axios: typeof Axios;
  AxiosError: typeof AxiosError;
  HttpStatusCode: typeof HttpStatusCode;
  readonly VERSION: string;
  isCancel: typeof isCancel;
  all: typeof all;
  spread: typeof spread;
  isAxiosError: typeof isAxiosError;
  toFormData: typeof toFormData;
  formToJSON: typeof formToJSON;
  getAdapter: typeof getAdapter;
  CanceledError: typeof CanceledError;
  AxiosHeaders: typeof AxiosHeaders;
}

declare const axios: AxiosStatic;

export default axios;

axios 기능을 가진 모듈을 작성할 때, 보통 export default axios와 같이 기본 내보내기를 사용합니다. 그러나 export와 export default의 차이를 이해하는 것이 중요합니다.

export default는 기본적으로 ES module을 따르며, 모듈당 하나의 기본 내보내기만 허용합니다. 이를 가져올 때에는 중괄호 없이 바로 이름을 지정하여 가져올 수 있습니다. 반면에 export는 여러 개의 변수나 함수를 내보낼 수 있으며, 가져올 때에는 중괄호와 함께 해당하는 이름을 지정하여 가져올 수 있습니다. export는 CommonJS 스타일의 require로 가져올 수 있습니다

axios는 AxiosStatic 인터페이스를 사용하고 AxiosInstance를 상속 받습니다.
AxiosInstance는 Axios 클래스를 상속을 받아 상속 순서는 다음과 같습니다.

AxiosStatic <- AxiosInstance <- Axios 순으로 상속을 합니다.

AxiosStatic와 AxiosInstance은 인터페이스를 사용하지만 Axios는 클래스를 사용합니다.
그렇기 때문에 Axois를 사용하는 방법은 3가지를 사용할 수 있습니다.

(async () => {
  try {
    new axios(); // 클래스 호출
    axios(); // 함수 호출
    axios.get(); // get 함수 호출
  } catch (error) {
    console.log(error)
  }
})();

이렇게 axios를 사용하는 방법은 프로젝트나 팀의 규모, 개발 환경 등에 따라 선택할 수 있습니다.

ts-node 사용하기

node.js는 JS로 구성이 되어 있습니다. 하지만 TS를 사용하려면 npx-tsc로 JS 파일로 변환 한 다음 실행을 해야 합니다.

node.js는 tsc로 사용하게끔 하는 ts-node 라이브러리를 사용하면 npx-tsc 명령어 입력 없이 실행 할 수 있습니다.

ts-node는 타입스크립트를 자바스크립트로 JIT 변환하여 사전 컴파일 없이 Node.js에서 타입스크립트를 직접 실행할 수 있게 해줍니다.

# Locally in your project.
npm install -D typescript
npm install -D ts-node

# Or globally with TypeScript.
npm install -g typescript
npm install -g ts-node

# Depending on configuration, you may also need these
npm install -D tslib @types/node

제네릭을 활용한 Response

axios.get 제네릭 함수는 Axios 라이브러리를 HTTP GET 요청을 수행하는 함수로 사용하고 있습니다. 제네릭을 사용하여 요청 시 반환되는 데이터의 타입을 명시 할 수 있습니다.

axios.get 내부 인터페이스 함수는 다음과 같이 구성되어 있습니다.

get<T = any, R = AxiosResponse<T>, D = any>(
   url: string, config?: AxiosRequestConfig<D>
): Promise<R>;

T는 요청 시 반환되는 데이터 타입을 의미합니다. 기본적으로 any가 지정이 되어 있어 어떤 타입도 사용 할 수 있습니다.
AxiosResponse<T>는 요청 받은 T 타입을 제네릭으로 받습니다. T 요청 타입을 AxiosResponse 인터페이스에서 요청을 처리해서 R로 함수의 반환 타입으로 나타냅니다.

이제 AxiosResponse 인터페이스를 수정하여 T가 어떻게 사용되는지 설명하겠습니다.

export interface AxiosResponse<T = any, D = any> {
  data: T; // HTTP 응답 데이터 타입
  status: number; // HTTP 상태 코드
  statusText: string; // HTTP 상태 메세지
  headers: RawAxiosResponseHeaders | AxiosResponseHeaders; // HTTP 응답 헤더
  config: InternalAxiosRequestConfig<D>; // Axios 요청 구성
  request?: any; // HTTP 요청 객체
}

AxiosResponse 제네릭의 T는 HTTP 응답에서 받은 데이터의 타입을 나타냅니다. data 속성은 axios.get 함수가 호출될 때 사용자가 명시한 제네릭 타입에 따라 동적으로 결정됩니다. 사용자는 임의로 데이터 타입을 정의할 수 있습니다.

interface Post { id: number, title: string, price: number, description: string, category: string }

(async () => {
  try {
    const response = await axios.get<Post>('https://fakestoreapi.com/products/1')
    console.log(response.data);
  } catch (error) {
    console.log(error)
  }
})();

axios.post 제네릭 함수는 Axios 라이브러리를 HTTP POST 요청을 수행하는 함수로 사용하고 있습니다.
axios.post 내부 인터페이스 함수는 다음과 같이 구성되어 있습니다.

post<T = any, R = AxiosResponse<T>, D = any>(
     url: string, data?: D, config?: AxiosRequestConfig<D>
): Promise<R>;

AxiosResponse 인터페이스는 GET 요청과 유사한 구조를 가지고 있지만 한 가지 특징이 있습니다. data?: D가 추가되어 있습니다.

export interface AxiosRequestConfig<D = any> {
  url?: string;
  method?: Method | string;
  baseURL?: string;
  transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];
  transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[];
  headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders;
  params?: any;
  paramsSerializer?: ParamsSerializerOptions | CustomParamsSerializer;
  data?: D;
}

AxiosRequest 제네릭의 D는 HTTP 요청에서 받은 데이터의 타입을 나타냅니다. data 속성은 axios.post 함수가 호출될 때 사용자가 명시한 데이터를 검증합니다.

const response = await axios.post<Created, AxiosResponse<Created>, Data>('https://fakestoreapi.com/products', {
  title: 'bar',
  price: 109.95,
  description: 'Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday',
  category: 'mens clothing'
})
console.log(response.data);

AxiosError와 unknown error 대처법

Axios는 AxiosError를 통해서 에러 처리를 합니다. try catch 문을 통해서 error 케이스를 알려줍니다.

하지만 AxiosError는 unknow을 사용하기 때문에 에러는 기본적으로 unknow로 구성되어 있습니다.

여기서 주의 해야 할 점은 Axios 에러만 발생 하는 것이 아니라 문법적 에러도 발생 할 수 있습니다.

그렇기 때문에 AxiosError 형변환을 시켜 Axios 에러를 발생하도록 변경해야 합니다.
response뒤 ?(물음표)는 옵셔널 체인으로 있을 수도 있고 아닐 수도 있다는 문법입니다.

(async () => {
  try {
    const response = await axios.post<Created, AxiosResponse<Created>, Data>('https://fakestoreapi.com/products', {
      title: 'bar',
      price: 109.95,
      description: 'Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday',
      category: 'mens clothing'
    })
  } catch (error) {
    console.error((error as AxiosError).response?.data)
  }
})();

AxiosError에서 문법적 에러를 처리하기 위해 타입 가드를 사용해서 에러 처리를 확실하게 할 수 있습니다.

(async () => {
  try {
    const response = await axios.post<Created, AxiosResponse<Created>, Data>('https://fakestoreapi.com/products', {
      title: 'bar',
      price: 109.95,
      description: 'Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday',
      category: 'mens clothing'
    })
  } catch (error) {
    if (error instanceof AxiosError) {
      error.response
    }
  }
})();

혹은 AxiosResponse로 error 메시지를 보내는 방법도 있습니다.

(async () => {
  try {
    const response = await axios.post<Created, AxiosResponse<Created>, Data>('https://fakestoreapi.com/products', {
      title: 'bar',
      price: 109.95,
      description: 'Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday',
      category: 'mens clothing'
    })
  } catch (error) {
    console.error((error.response as AxiosResponse< { messages: string } >).response?.data)
  }
})();

axios isAxiosError를 통해서 에러를 처리할 수 있습니다.
isAxiosError 함수 구조를 다음과 같습니다.

export function isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;

그럼 다음과 같이 구현이 가능합니다.

(async () => {
  try {
    const response = await axios.post<Created, AxiosResponse<Created>, Data>('https://fakestoreapi.com/products', {
      title: 'bar',
      price: 109.95,
      description: 'Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday',
      category: 'mens clothing'
    })
  } catch (error) {
    // export function isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;    
    if (axios.isAxiosError(error)) {
      console.error((error.response as AxiosResponse<{ messages: string }>)?.data.messages);
    }
  }
})();
profile
BackEnd Developer
post-custom-banner

0개의 댓글