개발 방법론 & 아키텍쳐

Zod + Zustand + React Query로 인증(Auth) 구현하기 (ErrorBoundary & AxiosInstance 사용)

atomicdev 2024. 9. 27. 10:21
728x90

Zod + Zustand + React Query로 인증(Auth) 구현하기 (feat. ErrorBoundary & AxiosInstance)

이번 섹션에서는 AxiosInstance를 활용하여 인증된 요청을 효율적으로 처리하는 방법을 설명합니다. 일반적으로 JWT 토큰을 사용한 인증은 로그인 후 accessToken을 HTTP 요청의 헤더에 추가해야 합니다. 이를 수동으로 처리하는 것은 번거롭기 때문에 AxiosInstance를 사용하여 이 작업을 자동화할 수 있습니다.

Zod , Zustand , React Query 를 활용한 인증 관리의 흐름


AxiosInstance를 사용한 인증 요청 처리

AxiosInstance 설정

axios는 interceptors를 제공하여 요청이 발생하기 전, 또는 응답이 반환되기 전에 특정 로직을 추가할 수 있습니다. 이 기능을 사용해 요청마다 JWT accessToken을 헤더에 추가하도록 설정할 수 있습니다.

먼저, axiosInstance.js 파일을 설정해 보겠습니다.

import axios from "axios";

// AxiosInstance 생성
const axiosInstance = axios.create({
  baseURL: "https://api.example.com", // API의 기본 URL
  timeout: 5000, // 타임아웃 설정
});

// 요청 인터셉터 설정
axiosInstance.interceptors.request.use(
  (config) => {
    const token = sessionStorage.getItem("accessToken"); // 세션 스토리지에서 토큰 가져오기
    if (token) {
      config.headers.Authorization = `Bearer ${token}`; // Authorization 헤더에 토큰 추가
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

export default axiosInstance;

인증이 필요한 API 요청

이제 AxiosInstance를 사용하여 인증이 필요한 API 요청을 처리하는 예제를 살펴보겠습니다. 여기서는 getMe()라는 함수를 만들어, 로그인 후 사용자 정보를 가져오는 요청을 처리합니다.

import { User } from "../model/auth";
import axiosInstance from "./axiosInstance";
import { z } from "zod";

// 사용자 정보 검증 스키마
const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string(),
});

// API로 사용자 정보 요청
export const getMe = async (): Promise<User> => {
  try {
    const { data } = await axiosInstance.get("/user/me");
    return UserSchema.parse(data); // Zod를 사용해 데이터 검증
  } catch (error) {
    console.error("Error fetching user data:", error);
    throw error;
  }
};

위 예제에서, axiosInstance는 요청을 보낼 때 accessToken을 자동으로 헤더에 포함시킵니다. 또한, Zod를 사용해 API 응답 데이터를 검증하고, 잘못된 데이터 형식이 있을 경우 오류를 던집니다.

AxiosInstance를 활용한 로그인 요청 처리

마찬가지로 로그인 요청에서도 axiosInstance를 사용할 수 있습니다. 로그인 성공 시 토큰을 받아 세션 스토리지에 저장하고, 이후 요청 시마다 이 토큰을 사용하게 됩니다.

import { z } from "zod";
import axiosInstance from "./axiosInstance";

// 로그인 요청 스키마
export const LoginResponse = z.object({
  token: z.string(),
});

export const login = async (loginParams: { id: string; password: string }) => {
  try {
    const { data } = await axiosInstance.post("/login", loginParams);
    const loginData = LoginResponse.parse(data); // Zod로 응답 데이터 검증
    sessionStorage.setItem("accessToken", loginData.token); // 세션 스토리지에 토큰 저장
    return loginData;
  } catch (error) {
    console.error("Login error:", error);
    throw error;
  }
};

위 코드는 사용자 인증 요청을 처리하며, 로그인에 성공하면 accessToken을 세션 스토리지에 저장합니다. 이후, 이 토큰은 axiosInstance의 인터셉터를 통해 모든 요청에 자동으로 포함됩니다.


전체적인 인증 로직

이제 AxiosInstance, Zod, Zustand, React Query를 결합한 전체적인 인증 로직을 정리하면 다음과 같습니다.

1. AxiosInstance 설정

axiosInstance를 설정하여 모든 요청에 accessToken을 자동으로 포함시킵니다.

2. 로그인 요청 처리

로그인 요청을 보내고, 성공 시 accessToken을 세션 스토리지에 저장합니다.

import { useMutation } from "@tanstack/react-query";
import { login, getMe } from "../api/auth";
import { useAuthStore } from "../store/auth";

export const useLogin = () => {
  const setUser = useAuthStore((state) => state.setUser);

  const { mutate, error, isError } = useMutation({
    mutationFn: login,
    onSuccess: async ({ token }) => {
      sessionStorage.setItem("accessToken", token);
      const user = await getMe();
      setUser(user);
    },
  });

  return { login: mutate, error, isError };
};

3. 사용자 정보 가져오기

로그인 후 사용자 정보를 가져오는 요청은 getMe()로 처리되며, Zod를 사용하여 API 응답 데이터를 검증합니다.

import { getMe } from "../api/auth";

export default function Profile() {
  const { data: user, isLoading, error } = useQuery("user", getMe);

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error loading user data</p>;

  return (
    <div>
      <h1>{user.name}'s Profile</h1>
      <p>Email: {user.email}</p>
    </div>
  );
}

결론

이 블로그 글에서는 AxiosInstance를 사용하여 JWT 토큰을 처리하는 방법을 소개했습니다. interceptors를 사용해 모든 요청에 자동으로 accessToken을 추가할 수 있으며, 이를 통해 인증된 API 요청을 쉽게 관리할 수 있습니다. 또한 ZodReact Query를 결합해 데이터 검증과 API 요청의 상태 관리를 효율적으로 처리하는 방법을 살펴보았습니다.

이러한 방법은 애플리케이션의 인증 로직을 간소화하고 유지보수를 쉽게 할 수 있게 도와줍니다.

728x90