Skip to content

Commit

Permalink
[Refactor] fetch instance 기능 보강 (#450)
Browse files Browse the repository at this point in the history
* feat: error 처리 로직 세분화를 위한 custom error 생성

* feat: params 처리

* feat: form data 처리

* refactor: instance 적용

* chore: fetcher로 이름 변경
  • Loading branch information
eonseok-jeon authored Sep 25, 2024
1 parent cf8a51f commit f6b0527
Show file tree
Hide file tree
Showing 15 changed files with 95 additions and 97 deletions.
45 changes: 45 additions & 0 deletions src/common/apis/fetcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const baseURL = import.meta.env.VITE_BASE_URL;

type StandardHeaders = 'Content-Type' | 'Authorization' | 'Accept' | 'Cache-Control' | 'User-Agent';
type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';

export class CustomError extends Error {
status: number;

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

interface FetchOptions extends Omit<RequestInit, 'body'> {
method?: RequestMethod;
headers?: Partial<Record<StandardHeaders, string>>;
body?: Record<string, unknown>;
params?: Record<string, any>;
}

const fetcher = async (url: string, options: FetchOptions = {}) => {
const { body, params, headers = {}, ...rest } = options;
const urlWithParams = params ? `${url}?${new URLSearchParams(params).toString()}` : url;
const isFormData = body instanceof FormData;

if (!isFormData) {
headers['Content-Type'] = 'application/json';
}

const response = await fetch(`${baseURL}${urlWithParams}`, {
headers,
body: isFormData ? body : JSON.stringify(body),
...rest,
});

if (!response.ok) {
const errMsg = await response.json();
throw new CustomError(errMsg.userMessage, response.status);
}

return response.json();
};

export default fetcher;
4 changes: 2 additions & 2 deletions src/common/apis/getRecruitingInfo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import instance from '@apis/instance';
import fetcher from '@apis/fetcher';

export const getRecruitingInfo = async () => {
const res = await instance('/recruiting-season/latest', { method: 'GET' });
const res = await fetcher('/recruiting-season/latest', { method: 'GET' });

return res;
};
27 changes: 0 additions & 27 deletions src/common/apis/instance.ts

This file was deleted.

20 changes: 10 additions & 10 deletions src/common/components/Input/apis.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
import instance from '@apis/instance';
import fetcher from '@apis/fetcher';

import { CheckUserRequest } from './types';

export const checkUser = async (userInfo: CheckUserRequest) => {
const { email, name, season, group } = userInfo;
const res = await instance('/recruiting-auth/check/user', {
const res = await fetcher('/recruiting-auth/check/user', {
method: 'POST',
body: JSON.stringify({
body: {
email,
name,
season,
group,
}),
},
});

return res;
};

export const sendVerificationCode = async (email: string, season: number, group: string, isSignup: boolean) => {
const res = await instance('/recruiting-auth/verify/send', {
const res = await fetcher('/recruiting-auth/verify/send', {
method: 'POST',
body: JSON.stringify({
body: {
email,
season,
group,
isSignup,
}),
},
});

return res;
};

export const checkVerificationCode = async (email: string, code: string) => {
const res = await instance('/recruiting-auth/verify/email', {
const res = await fetcher('/recruiting-auth/verify/email', {
method: 'POST',
body: JSON.stringify({
body: {
email,
code,
}),
},
});

return res;
Expand Down
9 changes: 4 additions & 5 deletions src/common/components/Input/hooks/useMutateCheckCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { VALIDATION_CHECK } from '@constants/validationCheck';
import { checkVerificationCode } from '../apis';

import type { CheckVerificationCodeRequest, EmailResponse } from '../types';
import type { ErrorResponse } from '@type/errorResponse';
import type { AxiosError, AxiosResponse } from 'axios';
import type { CustomError } from '@apis/fetcher';

interface MutateCheckCodeProps {
onSuccess: () => void;
Expand All @@ -17,14 +16,14 @@ const useMutateCheckCode = ({ onSuccess }: MutateCheckCodeProps) => {
const { setError } = useFormContext();

const { mutate: checkVerificationCodeMutate, isPending: checkVerificationCodeIsPending } = useMutation<
AxiosResponse<EmailResponse, CheckVerificationCodeRequest>,
AxiosError<ErrorResponse, CheckVerificationCodeRequest>,
EmailResponse,
CustomError,
CheckVerificationCodeRequest
>({
mutationFn: ({ email, code }: CheckVerificationCodeRequest) => checkVerificationCode(email, code),
onSuccess,
onError(error) {
if (error.response?.status === 400) {
if (error.status === 400) {
setError('code', {
type: 'not-match',
message: VALIDATION_CHECK.verificationCode.errorText,
Expand Down
9 changes: 4 additions & 5 deletions src/common/components/Input/hooks/useMutateCheckUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { VALIDATION_CHECK } from '@constants/validationCheck';
import { checkUser } from '../apis';

import type { CheckUserRequest, EmailResponse } from '../types';
import type { ErrorResponse } from '@type/errorResponse';
import type { AxiosError, AxiosResponse } from 'axios';
import type { CustomError } from '@apis/fetcher';

interface MutateCheckUserProps {
onSendCode: () => void;
Expand All @@ -17,8 +16,8 @@ const useMutateCheckUser = ({ onSendCode }: MutateCheckUserProps) => {
const { clearErrors, setError } = useFormContext();

const { mutate: checkUserMutate, isPending: checkUserIsPending } = useMutation<
AxiosResponse<EmailResponse, CheckUserRequest>,
AxiosError<ErrorResponse, CheckUserRequest>,
EmailResponse,
CustomError,
CheckUserRequest
>({
mutationFn: (userInfo: CheckUserRequest) => checkUser(userInfo),
Expand All @@ -27,7 +26,7 @@ const useMutateCheckUser = ({ onSendCode }: MutateCheckUserProps) => {
onSendCode();
},
onError: (error) => {
if (error.response?.status === 400 || error.response?.status === 403) {
if (error.status === 400 || error.status === 403) {
setError('name', {
type: 'non-existence',
message: VALIDATION_CHECK.name.errorTextNonexistence,
Expand Down
9 changes: 4 additions & 5 deletions src/common/components/Input/hooks/useMutateSendCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { VALIDATION_CHECK } from '@constants/validationCheck';
import { sendVerificationCode } from '../apis';

import type { EmailResponse, SendVerificationCodeRequest } from '../types';
import type { ErrorResponse } from '@type/errorResponse';
import type { AxiosError, AxiosResponse } from 'axios';
import type { CustomError } from '@apis/fetcher';

interface MutateSendCodeProps {
onChangeVerification: (bool: boolean) => void;
Expand All @@ -18,8 +17,8 @@ const useMutateSendCode = ({ onChangeVerification, onSetTimer }: MutateSendCodeP
const { setError } = useFormContext();

const { mutate: sendVerificationCodeMutate, isPending: sendVerificationCodeIsPending } = useMutation<
AxiosResponse<EmailResponse, SendVerificationCodeRequest>,
AxiosError<ErrorResponse, SendVerificationCodeRequest>,
EmailResponse,
CustomError,
SendVerificationCodeRequest
>({
mutationFn: ({ email, season, group, isSignup }: SendVerificationCodeRequest) =>
Expand All @@ -29,7 +28,7 @@ const useMutateSendCode = ({ onChangeVerification, onSetTimer }: MutateSendCodeP
onSetTimer();
},
onError: (error) => {
if (error.response?.status === 400 || error.response?.status === 403) {
if (error.status === 400 || error.status === 403) {
setError('email', {
type: 'already-existence',
message: VALIDATION_CHECK.email.errorTextExistence,
Expand Down
4 changes: 2 additions & 2 deletions src/common/hooks/useDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const useDate = () => {
obInterviewStart,
ybInterviewEnd,
obInterviewEnd,
} = data?.data.season || {};
} = data?.season || {};

const applicationStart = group === 'YB' ? ybApplicationStart : obApplicationStart; // 서류 시작
const applicationEnd = group === 'YB' ? ybApplicationEnd : obApplicationEnd; // 서류 마감
Expand Down Expand Up @@ -98,7 +98,7 @@ const useDate = () => {
]);

return {
...data?.data.season,
...data?.season,
NoMoreRecruit,
NoMoreApply,
NoMoreScreeningResult,
Expand Down
10 changes: 2 additions & 8 deletions src/common/hooks/useGetRecruitingInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@ import { useQuery } from '@tanstack/react-query';

import { getRecruitingInfo } from '@apis/getRecruitingInfo';

import type { ErrorResponse } from '@type/errorResponse';
import type { RecruitingResponse } from '@type/recruitingInfo';
import type { AxiosError, AxiosResponse } from 'axios';
import type { CustomError } from '@apis/fetcher';

const useGetRecruitingInfo = () => {
const { data, isLoading } = useQuery<
AxiosResponse<RecruitingResponse, null>,
AxiosError<ErrorResponse, null>,
AxiosResponse<RecruitingResponse, null>,
string[]
>({
const { data, isLoading } = useQuery<RecruitingResponse, CustomError, RecruitingResponse, string[]>({
queryKey: ['get-recruiting-info'],
queryFn: getRecruitingInfo,
});
Expand Down
8 changes: 4 additions & 4 deletions src/views/PasswordPage/apis.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import instance from '@apis/instance';
import fetcher from '@apis/fetcher';

import type { PasswordRequest } from './types';

export const sendPasswordChange = async (userInfo: PasswordRequest) => {
const { email, season, group, password, passwordCheck } = userInfo;
const res = await instance('/recruiting-auth/change/password', {
const res = await fetcher('/recruiting-auth/change/password', {
method: 'POST',
body: JSON.stringify({
body: {
email,
season,
group,
password,
passwordCheck,
}),
},
});

return res;
Expand Down
7 changes: 3 additions & 4 deletions src/views/PasswordPage/hooks/useMutateChangePassword.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { useMutation } from '@tanstack/react-query';
import { AxiosError, AxiosResponse } from 'axios';

import { sendPasswordChange } from '../apis';

import type { PasswordRequest, PasswordResponse } from '../types';
import type { ErrorResponse } from '@type/errorResponse';
import type { CustomError } from '@apis/fetcher';

interface MutateChangePasswordProps {
onSuccess: () => void;
}

const useMutateChangePassword = ({ onSuccess }: MutateChangePasswordProps) => {
const { mutate: changePasswordMutate, isPending: changePasswordIsPending } = useMutation<
AxiosResponse<PasswordResponse, PasswordRequest>,
AxiosError<ErrorResponse, PasswordRequest>,
PasswordResponse,
CustomError,
PasswordRequest
>({
mutationFn: (userInfo: PasswordRequest) => sendPasswordChange(userInfo),
Expand Down
8 changes: 4 additions & 4 deletions src/views/SignInPage/apis.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import instance from '@apis/instance';
import fetcher from '@apis/fetcher';

import type { SignInRequest } from './types';

export const sendSignIn = async (userInfo: SignInRequest) => {
const { email, season, group, password } = userInfo;
const res = await instance('/recruiting-auth/login', {
const res = await fetcher('/recruiting-auth/login', {
method: 'POST',
body: JSON.stringify({
body: {
email,
season,
group,
password,
}),
},
});

return res;
Expand Down
13 changes: 4 additions & 9 deletions src/views/SignInPage/hooks/useMutateSignIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,24 @@ import { VALIDATION_CHECK } from '@constants/validationCheck';
import { sendSignIn } from '../apis';

import type { SignInRequest, SignInResponse } from '../types';
import type { ErrorResponse } from '@type/errorResponse';
import type { AxiosError, AxiosResponse } from 'axios';
import type { CustomError } from '@apis/fetcher';

interface MutateSignInProps {
finalPassConfirmEnd?: string;
onSetError: (name: string, type: string, message: string) => void;
}

const useMutateSignIn = ({ finalPassConfirmEnd, onSetError }: MutateSignInProps) => {
const { mutate: signInMutate, isPending: signInIsPending } = useMutation<
AxiosResponse<SignInResponse, SignInRequest>,
AxiosError<ErrorResponse, SignInRequest>,
SignInRequest
>({
const { mutate: signInMutate, isPending: signInIsPending } = useMutation<SignInResponse, CustomError, SignInRequest>({
mutationFn: (userInfo: SignInRequest) => sendSignIn(userInfo),
onSuccess: ({ data: { email, token } }) => {
onSuccess: ({ email, token }) => {
setUserId(email);
localStorage.setItem('soptApplyAccessToken', token);
localStorage.setItem('soptApplyAccessTokenExpiredTime', finalPassConfirmEnd || '');
window.location.reload();
},
onError(error) {
if (error.response?.status === 403) {
if (error.status === 403) {
onSetError('email', 'not-match', VALIDATION_CHECK.email.notMatchErrorText);
onSetError('password', 'not-match', VALIDATION_CHECK.password.notMatchErrorText);
}
Expand Down
8 changes: 4 additions & 4 deletions src/views/SignupPage/apis.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import instance from '@apis/instance';
import fetcher from '@apis/fetcher';

import type { SignUpRequest } from './types';

export const sendSignUp = async (userInfo: SignUpRequest) => {
const { email, password, passwordCheck, name, phone, season, group } = userInfo;
const res = await instance('/recruiting-auth/signup', {
const res = await fetcher('/recruiting-auth/signup', {
method: 'POST',
body: JSON.stringify({
body: {
email,
password,
passwordCheck,
name,
phone,
season,
group,
}),
},
});

return res;
Expand Down
Loading

0 comments on commit f6b0527

Please sign in to comment.