npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cher1shrxd/api-client

v1.0.4

Published

Next.js SSR 환경에서 쿠키 전달을 지원하는 API 클라이언트

Readme

@cher1shrxd/api-client

Next.js SSR 환경에서 쿠키 전달을 지원하는 API 클라이언트

설치

pnpm add @cher1shrxd/api-client

설정

기본 설정

// lib/api.ts
import { createApiClient } from "@cher1shrxd/api-client";

export const apiClient = createApiClient({
  baseURL: process.env.NEXT_PUBLIC_API_URL!,
});

전체 설정

// lib/api.ts
import { createApiClient } from "@cher1shrxd/api-client";

export const apiClient = createApiClient({
  // 필수
  baseURL: process.env.NEXT_PUBLIC_API_URL!,

  // 선택
  timeout: 10000,
  headers: {
    "X-Custom-Header": "value",
  },
  withCredentials: true,
  debug: process.env.NODE_ENV === "development",

  // 서버사이드 쿠키 설정
  // cookieNames에 등록된 쿠키가 실제로 저장되어 있지 않다면 redirectPath로 페이지 이동
  serverCookieConfig: {
    cookieNames: ["SESSION", "SESSION-LOCAL"],
    redirectPath: "/login", // null로 설정시 리다이렉트 비활성화
  },

  // 인터셉터 콜백
  interceptors: {
    onRequest: (config) => {
      const token = getToken();
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    },
    onResponseError: (error) => {
      if (error.response?.status === 401) {
        window.location.href = "/login";
      }
      return Promise.reject(error);
    },
  },

  // 또는 setupInterceptors로 직접 제어 (기본 인터셉터 대체)
  // setupInterceptors: (instance) => {
  //   instance.interceptors.request.use(...);
  // },
});

사용법

기본 요청

import { apiClient } from "@/lib/api";

// GET
const users = await apiClient.get<User[]>("/users");
console.log(users.data);

// POST
const newUser = await apiClient.post<User>("/users", {
  name: "John",
  email: "[email protected]",
});

// PUT
await apiClient.put("/users/1", { name: "Updated" });

// PATCH
await apiClient.patch("/users/1", { name: "Patched" });

// DELETE
await apiClient.delete("/users/1");

쿠키 전달 (서버 컴포넌트)

// Server Component 또는 API Route에서
const profile = await apiClient
  .get<Profile>("/profile")
  .withCookie();

// 요청 헤더에 쿠키가 자동으로 포함됨

요청 설정

const response = await apiClient.get<Data>("/data", {
  params: { page: 1, limit: 10 },
  headers: { "X-Request-ID": "123" },
});

타입 지정

interface User {
  id: number;
  name: string;
  email: string;
}

// 응답 타입: HttpResponse<User[]>
const response = await apiClient.get<User[]>("/users");

// data 타입: User[]
const users = response.data;

에러 처리

import { isHttpError } from "@cher1shrxd/api-client";

try {
  const response = await apiClient.get<User>("/users/999");
} catch (error) {
  if (isHttpError(error)) {
    console.error(error.response?.status); // 404
    console.error(error.response?.data);
  }
}

HTTP 인스턴스 접근

const httpInstance = apiClient.getHttpInstance();

// 생성 후 커스텀 인터셉터 추가
httpInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      // 인증 실패 처리
    }
    return Promise.reject(error);
  }
);

인터셉터

콜백 방식 (권장)

interceptors 옵션으로 인터셉터를 추가합니다. 기본 인터셉터 이후에 실행됩니다.

const apiClient = createApiClient({
  baseURL: "https://api.example.com",
  interceptors: {
    // 요청 전 설정 수정
    onRequest: (config) => {
      config.headers.Authorization = `Bearer ${getToken()}`;
      return config;
    },

    // 요청 에러 처리
    onRequestError: (error) => {
      console.error("Request failed:", error);
      return Promise.reject(error);
    },

    // 응답 변환
    onResponse: (response) => {
      console.log("Response:", response.status);
      return response;
    },

    // 응답 에러 처리 (401, 500 등)
    onResponseError: async (error) => {
      if (error.response?.status === 401) {
        await refreshToken();
        return apiClient.getHttpInstance().request(error.config!);
      }
      return Promise.reject(error);
    },
  },
});

setupInterceptors 방식 (직접 제어)

setupInterceptors를 사용하면 기본 인터셉터를 완전히 대체합니다.

const apiClient = createApiClient({
  baseURL: "https://api.example.com",
  setupInterceptors: (instance) => {
    instance.interceptors.request.use(
      (config) => {
        // 직접 구현
        return config;
      },
      (error) => Promise.reject(error)
    );

    instance.interceptors.response.use(
      (response) => response,
      (error) => Promise.reject(error)
    );
  },
});

setupInterceptors 사용시 기본 디버그 로깅 인터셉터가 적용되지 않습니다.

API

createApiClient(options)

| 옵션 | 타입 | 기본값 | 설명 | |------|------|--------|------| | baseURL | string | 필수 | 요청 기본 URL | | timeout | number | 10000 | 요청 타임아웃 (ms) | | headers | Record<string, string> | {} | 기본 헤더 | | withCredentials | boolean | true | 자격 증명 포함 여부 | | debug | boolean | false | 콘솔 로깅 활성화 | | serverCookieConfig | ServerCookieConfig | undefined | 서버 쿠키 설정 | | interceptors | InterceptorCallbacks | undefined | 인터셉터 콜백 | | setupInterceptors | (instance) => void | undefined | 커스텀 인터셉터 (기본값 대체) |

InterceptorCallbacks

| 옵션 | 타입 | 설명 | |------|------|------| | onRequest | (config) => config | 요청 설정 수정 | | onRequestError | (error) => Promise.reject(error) | 요청 에러 처리 | | onResponse | (response) => response | 응답 수정 | | onResponseError | (error) => Promise.reject(error) | 응답 에러 처리 |

ServerCookieConfig

| 옵션 | 타입 | 설명 | |------|------|------| | cookieNames | string[] | 인증 확인할 쿠키 이름 목록 | | redirectPath | string \| null | 인증 없을 때 리다이렉트 경로 (null시 비활성화) |

ApiClient 메서드

| 메서드 | 시그니처 | |--------|----------| | get | <T>(url, config?) => ApiRequest<T> | | post | <T>(url, data?, config?) => ApiRequest<T> | | put | <T>(url, data?, config?) => ApiRequest<T> | | patch | <T>(url, data?, config?) => ApiRequest<T> | | delete | <T>(url, config?) => ApiRequest<T> | | getHttpInstance | () => HttpInstance |

ApiRequest 메서드

| 메서드 | 설명 | |--------|------| | .withCookie() | 쿠키 전달 활성화 | | .execute() | 요청 실행 (Promise 반환) | | .then() | Promise then 핸들러 | | .catch() | Promise catch 핸들러 | | .finally() | Promise finally 핸들러 |

Peer Dependencies

  • next >= 14.0.0

License

MIT