Next.js | class 로 api 호출 로직을 만들어보자

Lumpen·2024년 10월 30일

Next.js

목록 보기
7/10
import { getSequence } from "../../lib/get-sequence";

class Apis {
  readonly baseUrl: string;

  constructor() {
    this.baseUrl = `${process.env.NEXT_PUBLIC_API_URL}`;
  }
  async handleError(response: Response) {
    const { status } = response;
    const { message } = await response.json();
    alert(message);
    console.log(`Error: ${status}, Message: ${message || "Unknown error"}`);
  }
}

class adminApis extends Apis {
  token: string | undefined = undefined;
  sequence: number | undefined = undefined;

  constructor(token: string) {
    super();
    this.token = token;
  }

  async getVisitor() {
    const { baseUrl, token } = this;
    try {
      return await fetch(`${baseUrl}/api/user/visitor`, {
        method: "GET",
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
    } catch (error) {
      console.log(error);
    }
  }

  async addBlock(params: { [index: string]: string | number | object | null }) {
    const { baseUrl, token } = this;
    if (!token) {
      alert("로그인이 필요합니다.");
      return;
    }
    if (!this.sequence) {
      const sequence = await getSequence(token);
      if (!sequence) {
        alert("시퀀스 조회 실패");
        return;
      }
      this.sequence = sequence;
    } else params["sequence"] = this.sequence + 1;

    try {
      const response = await fetch(`${baseUrl}/api/link/add`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
        body: JSON.stringify(params),
      });

      if (response.ok) {
        this.sequence = this.sequence + 1;
        return response;
      } else {
        return response;
      }
    } catch (error) {
      throw new Error(
        error instanceof Error ? error.message : "알 수 없는 에러",
      );
    }
  }

  async getBlocks() {
    const { baseUrl, token } = this;
    try {
      return await fetch(`${baseUrl}/api/link/list`, {
        method: "GET",
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
    } catch (error) {
      console.log(error);
    }
  }
}

class AuthApis extends Apis {
  async login(userId: string, password: string) {
    try {
      return await fetch(`${this.baseUrl}/api/login`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          userId: userId,
          password: password,
        }),
      });
    } catch (error) {
      console.log(error);
    }
  }
}

const getInstance = async (type?: string) => {
  if (!type) return new Apis();
  if (type === "block") {
    if (typeof window === "undefined") return;
    const token = window.sessionStorage.getItem("token");
    if (!token) {
      return;
    }
    return new adminApis(token);
  }
  if (type === "auth") return new AuthApis();
};

const adminApiInstance = getInstance("block") as Promise<adminApis>;
const authApiInstance = getInstance("auth") as Promise<AuthApis>;

export { adminApiInstance, authApiInstance };

api 로직을 사용하지 않더라도 instance 를 생성한다는 단점이 있다
현재 코드에서는 페이지에 접근하지 않더라도 instance 를 생성..

함수와 변수로 작성하는 것 보다는 조금 더 통일성 있고 직관적인 느낌이긴 한데
굳이 필요할까 싶기도 한
그래도 상속과 오버라이딩이 되니까 편한 것 같기도 하고..

getInstance block 타입의 경우 token 이 없는 경우의 처리를
페이지에서 instance 없을 시 이런 방식으로 처리하고 있는데
고차 컴포넌트를 사용해서 isLoggedIn 처리를 한다면 필요하지 않은 코드일 수도..

profile
암흑개발자

0개의 댓글