From 00c794bbbbcd1cc506a9febb9c7961c8a6578de4 Mon Sep 17 00:00:00 2001 From: Jeongmin Lee Date: Thu, 15 Aug 2024 19:47:40 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20fetch=20=EC=B6=94=EC=83=81?= =?UTF-8?q?=ED=99=94=20=EC=9E=91=EC=97=85=20#23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/error.ts | 58 ++++++++++++++++++++++++++ src/apis/instance.ts | 98 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/apis/error.ts create mode 100644 src/apis/instance.ts diff --git a/src/apis/error.ts b/src/apis/error.ts new file mode 100644 index 0000000..c4894d4 --- /dev/null +++ b/src/apis/error.ts @@ -0,0 +1,58 @@ +export class FiestaError extends Error { + public statusCode: number; + public code: string; + + constructor(statusCode: number, code: string, message: string) { + super(message); + this.statusCode = statusCode; + this.code = code; + this.name = this.constructor.name; + } +} + +// 서버 에러 클래스 +export class ServerError extends FiestaError { + constructor(code: string, message: string) { + super(500, code, message); + } +} + +// 클라이언트 에러 클래스 +export class ClientError extends FiestaError { + constructor(statusCode: number, code: string, message: string) { + super(statusCode, code, message); + } +} +// 페스티벌 에러 클래스 +export class FestivalError extends FiestaError { + constructor(statusCode: number, code: string, message: string) { + super(statusCode, code, message); + } +} +// 방문일지 에러 클래스 +export class LogsError extends FiestaError { + constructor(statusCode: number, code: string, message: string) { + super(statusCode, code, message); + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function createFiestaError(error: any) { + const { code, message, statusCode } = error; + const initial = error.code.charAt(0); + + if (initial === "S") { + return new ServerError(code, message); + } + if (initial === "C") { + return new ClientError(statusCode, code, message); + } + if (initial === "F") { + return new FestivalError(statusCode, code, message); + } + if (initial === "L") { + return new ClientError(statusCode, code, message); + } + + return new Error("Something went wrong"); +} diff --git a/src/apis/instance.ts b/src/apis/instance.ts new file mode 100644 index 0000000..f273a33 --- /dev/null +++ b/src/apis/instance.ts @@ -0,0 +1,98 @@ +import { env } from "@/env"; + +import { + ClientError, + createFiestaError, + FestivalError, + LogsError, + ServerError, +} from "./error"; + +export type Method = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; + +export interface FiestaResponse { + statusCode: number; + status: string; + message: string; + data: T; +} + +const fiestaFetch = async ( + url: string, + method: Method, + options: RequestInit, +) => { + const baseUrl = env.NEXT_PUBLIC_BASE_URL; + + const _defaultOptions: RequestInit = { + headers: { + "Content-Type": "application/json", + }, + }; + + const finalOptions = { + method, + ..._defaultOptions, + ...options, + headers: { + ..._defaultOptions.headers, + ...options?.headers, + }, + }; + + try { + const response = await fetch(baseUrl + url, finalOptions); + if (!response.ok) { + const errorData = await response.json(); + const fiestaError = createFiestaError(errorData); + throw fiestaError; + } + return await response.json(); + } catch (error: unknown) { + console.error(error); + + if (error instanceof ServerError) { + // TODO: Server Error + throw error; + } + if (error instanceof ClientError) { + // TODO: Client Error + throw error; + } + if (error instanceof FestivalError) { + // TODO: Festival Error + throw error; + } + if (error instanceof LogsError) { + // TODO: Logs Error + throw error; + } + + throw error; + } +}; + +const instance = { + get: async ( + url: string, + options: Omit = {}, + ): Promise> => fiestaFetch(url, "GET", options), + post: async ( + url: string, + body = {}, + options: Omit = {}, + ): Promise> => + fiestaFetch(url, "POST", { body: JSON.stringify(body), ...options }), + put: async ( + url: string, + body = {}, + options: Omit = {}, + ): Promise> => + fiestaFetch(url, "PUT", { body: JSON.stringify(body), ...options }), + delete: async ( + url: string, + options: Omit = {}, + ): Promise> => fiestaFetch(url, "DELETE", { ...options }), +}; + +export default instance;