본문으로 바로가기

어떤 식으로 서버와의 통신을 하는지, 어떤 data가 들어오는 지에 따라 적절한 탑레벨 http api handler를 만들어주는 것이 좋다. 

일관된 처리를 위해서 필요하다. 

 

1. 응답 객체는 일관성이 있어야 관리하기 쉬워진다.

 

타입스크립트던 뭐던 타입이 있는 언어를 백엔드로 채택하는 이유 중 하나이다. 요새 JAVA가 왜 자주 쓰이는지 알 것 같기도 하다.

 

 

아래 코드는 적절한 로직을 처리한 후 success 필드의 boolean값을 통해 해당 로직이 성공적으로 이루어졌는지, 아닌지를 프론트에서 체크하도록 만들었다. 백엔드에서 이 형식의 일관성을 지치는 것은 중요하다. 특정 요청이 성공했는지의 여부를 판단하는 필드가 엔드포인트마다 다르다면 지옥을 맛볼 수 있을 것이다.

 

가급적, return 하는 형식에 typing을 해주어서 일관된 코드를 작성할 수 있도록 강제하는 것이 좋다.

예를 들어 interface ResponseWithTyped extends Resposne = { success: boolean; }; 꼴로 extends 하자.

 

아래는 이런 작업을 안했던 옛날 코드인데, 타입 체킹이 이루어지고 있지 않아서 타이핑 실수가 발생하기 쉬운 구조를 가지고 있다.

oAuthRouter.post("/google/login", async (req, res, next) => {
  // do some logic
  
  try {
    // do some logic
    return res.status(200).json({success: true, token, ...userInfo});
  } catch(error) {
    return res.status(500).json({success: false, error})
  }
  
});

 

한편, error 처리 미들웨어를 통한 에러 미들웨어 작성도 마찬가지이다. 아래와 같이 일정한 형식을 지켜준다면, 일관성 있는 응답을 보낼 수 있다. HttpException 에러로 타이핑으로 구조를 잡아주고, 일관성 있는 응답 객체를 만들도록하자.

class HttpException extends Error {
  public status: number;
  public message: string;

  constructor(status: number, message: string) {
    super(message);
    this.status = status;
    this.message = message;
  }
}

export default HttpException;
const errorMiddleware = (error: HttpException, req: Request, res: Response, next: NextFunction) => {
  try {
    const status: number = error.status || 500;
    const message: string = error.message || 'Something went wrong';

    if (process.env.NODE_ENV === 'development') {
      console.log('백엔드에서 에러가 났습니다.');
      console.log(error);
    }
    logger.error(`StatusCode : ${status}, Message : ${message}`);
    return res.status(status).json({ success: false, error: message });
  } catch (error) {
    next(error);
  }
};

 

 

2. 응답의 타입이 일관된다면  요청의 주체인 프론트는 중앙 집중식으로 요청에 대한 처리를 할 수 있게 된다.

물론 어떤 상태 관리 라이브러리를 사용하는지 등에 따라 코드는 달라지기 마련이다.

got, axios, fetch, xhr 뭘 쓸지, 상태 관리는 SWR, redux, mobx, apollo 중 무엇을 쓸 것인지 등등.

 

고민하던 중 유튜브에서 라이브 코딩을 보던 중 다음과 같은  useApiWrapper를 보게 되어 첨부해본다. (멍개)

이런식으로 작성한다는 아이디어만 가져가도록하자.

 

 

제가 만든 api handler입니다. 다른 프로젝트를 사면서 계속 발전시켜보겠습니다.

import axios, { Method, AxiosResponse } from 'axios';

interface HttpResHandler {
  success(): void;
  error(error: Error | string): void;
}

export interface HttpRes extends AxiosResponse<{ success: boolean }> {}

function apiWrapper<T>(path: string, method: Method, body: object, httpResHandler: HttpResHandler) {
  const host = 'api gateway endpoint';
  const url = host + path;

  const call = async (): Promise<HttpRes> => {
    const response = axios({
      method,
      url,
      data: body,
      timeout: 2000,
    });

    return response;
  };

  const httpResHandling = async () => {
    try {
      const response = await call();
      console.log(`resonse is ${response}`);

      if (response.data.success) {
        httpResHandler.success();
      }
    } catch (error) {
      httpResHandler.error(error);
    }
  };

  httpResHandling();
}

export default apiWrapper;

 

ref)

https://ui.toast.com/weekly-pick/ko_20200623

https://blog.naver.com/pjt3591oo/222305175450

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체