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

axios-impostor

v1.6.1

Published

**繁體中文** | [English](./README.md)

Readme

繁體中文 | English

Axios Impostor 🎭

輕量級的 HTTP 客戶端,API 設計類似 Axios。這份說明專注在:怎麼用有哪些型別建議的專案結構

安裝

npm install axios-impostor
# 或
pnpm add axios-impostor
# 或
yarn add axios-impostor

1. 建議的使用方式

在你的專案裡,建議這樣拆:

  1. 建立一個共用的 client 實例
    • 放在像是 src/api/client.ts 的檔案裡。
    • 在這裡設定 baseURLtimeout、預設 headers、interceptors 等。
  2. 每個領域/模組各自一組 API 函式
    • 例如 src/api/users.ts 裡面只放「使用者相關」的 API。
    • 這些函式內部呼叫 client 方法,回傳明確的型別。
  3. 錯誤處理集中在 UI 或服務層
    • 當需要依 HTTP 狀態碼、錯誤 code 做判斷時,使用 FetchClientError
  4. SSE 相關放在獨立模組
    • 例如 src/api/stream.ts,用於聊天室、通知、AI 串流等。

2. 快速開始範例

import { createFetchClient, FetchClientError } from 'axios-impostor';

// 1. 定義後端回傳的資料型別
interface User {
  id: number;
  name: string;
  email: string;
}

// 2. 建立共用 client(建議放在 src/api/client.ts)
export const api = createFetchClient({
  baseURL: 'https://jsonplaceholder.typicode.com',
  timeout: 10000,
});

// 3. 建立 endpoint 輔助函式(例如放在 src/api/users.ts)
export async function getUser(userId: number): Promise<User> {
  const response = await api.get<User>(`/users/${userId}`);
  return response.data; // 取出實際的使用者資料
}

export async function createUser(input: Pick<User, 'name' | 'email'>): Promise<User> {
  const response = await api.post<User, typeof input>('/users', input);
  return response.data;
}

// 4. 在 UI / service 內使用
async function example() {
  try {
    const user = await getUser(1);
    console.log('User name:', user.name);
  } catch (error) {
    if (error instanceof FetchClientError) {
      console.error('請求失敗', {
        code: error.code,
        status: error.response?.status,
        url: error.config.url,
      });
    }
    throw error;
  }
}

3. 理解 FetchResponse

所有 HTTP 方法(getpostputpatchdelete)都回傳 FetchResponse<T> 物件:

interface FetchResponse<T> {
  data: T; // ← 你的後端回應資料
  status: number; // ← HTTP 狀態碼(200、404 等)
  statusText: string; // ← 狀態文字("OK"、"Not Found" 等)
  headers: Headers; // ← 回應標頭
  config: CustomRequestInit; // ← 使用的請求設定
}

為什麼要包裝回應?

這讓你可以同時存取資料和中繼資料:

const response = await api.get<User>('/users/1');

// 存取資料
console.log(response.data.name);

// 檢查狀態
if (response.status === 200) {
  console.log('成功!');
}

// 讀取標頭
const contentType = response.headers.get('Content-Type');

// 查看請求了什麼
console.log('請求:', response.config.url);

如果你偏好不包裝的資料:

只要在輔助函式中取出 .data 即可(如快速開始範例所示)。


4. SSE 串流範例

用於 Server-Sent Events(聊天、AI 回應、即時更新):

import { api } from './client';
import type { SSEMessage, SSEConnection } from 'axios-impostor';

export function subscribeChat(roomId: string, onMessage: (data: unknown) => void): SSEConnection {
  const connection = api.sse(`/chat/rooms/${roomId}/stream`, {
    headers: {
      Authorization: 'Bearer your-token',
    },
    onOpen: () => {
      console.log('SSE 已連線');
    },
    onMessage: (message: SSEMessage) => {
      // 大多數後端會在 message.data 中傳送 JSON
      try {
        const parsed = JSON.parse(message.data);
        onMessage(parsed);
      } catch {
        onMessage(message.data);
      }
    },
    onError: (error) => {
      console.error('SSE 錯誤', error);
    },
    onClose: () => {
      console.log('SSE 已關閉');
    },
  });

  return connection;
}

// 使用方式
const connection = subscribeChat('room-1', (payload) => {
  console.log('聊天更新:', payload);
});

// 停止監聽
connection.close();

5. API 參考

createFetchClient(options?)

建立可重複使用的 HTTP 客戶端。

選項(CreateFetchClientProp):

| 選項 | 型別 | 說明 | | ------------- | -------------------- | ------------------------------------------------------- | | baseURL | string | 所有請求前綴的基礎 URL | | headers | HeadersInit | 所有請求的預設標頭 | | timeout | number | 預設逾時時間(毫秒) | | credentials | RequestCredentials | Cookie 策略:'omit' | 'same-origin' | 'include' |

回傳(FetchClient):

interface FetchClient {
  // HTTP 方法 - 所有都回傳 FetchResponse<T>
  get<T>(endpoint: string, options?: CustomRequestInit): Promise<FetchResponse<T>>;
  post<T, B>(endpoint: string, body?: B, options?: CustomRequestInit): Promise<FetchResponse<T>>;
  put<T, B>(endpoint: string, body?: B, options?: CustomRequestInit): Promise<FetchResponse<T>>;
  patch<T, B>(endpoint: string, body?: B, options?: CustomRequestInit): Promise<FetchResponse<T>>;
  delete<T>(endpoint: string, options?: CustomRequestInit): Promise<FetchResponse<T>>;

  // 串流
  sse(endpoint: string, options: SSEOptions): SSEConnection;

  // 攔截器
  interceptors: {
    request: InterceptorManager<CustomRequestInit>;
    response: InterceptorManager<Response>;
  };
}

特殊行為:

  • 所有方法都會自動解析 JSON
  • 204 No Content 回傳 { data: null, status: 204, ... }
  • 非 2xx 狀態碼會拋出 FetchClientError

攔截器

新增全域的請求/回應處理:

// 為所有請求加上 auth token
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers = {
      ...config.headers,
      Authorization: `Bearer ${token}`,
    };
  }
  return config;
});

// 全域處理 401
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error instanceof FetchClientError && error.response?.status === 401) {
      // 重導向到登入頁
      window.location.href = '/login';
    }
    throw error;
  },
);

6. 型別參考

FetchResponse<T>

所有 HTTP 方法回傳的包裝回應物件:

interface FetchResponse<T> {
  data: T; // 你的型別化回應資料
  status: number; // HTTP 狀態碼
  statusText: string; // 狀態訊息
  headers: Headers; // 回應標頭
  config: CustomRequestInit; // 使用的請求設定
}

CustomRequestInit

擴展原生 RequestInit

interface CustomRequestInit extends RequestInit {
  timeout?: number; // 單次請求的逾時覆寫
  isStream?: boolean; // 內部旗標(自動管理)
  url?: string; // 內部設定
  baseURL?: string; // 內部設定
}

FetchClientError

請求失敗時拋出:

class FetchClientError extends Error {
  code?: string; // 'ERR_NETWORK', 'ERR_BAD_RESPONSE', 'ECONNABORTED'
  config: CustomRequestInit; // 失敗的請求
  request?: Request; // 原生 Request 物件
  response?: Response; // 原生 Response 物件(如果有的話)
}

用於錯誤處理:

try {
  await api.get('/data');
} catch (error) {
  if (error instanceof FetchClientError) {
    if (error.code === 'ECONNABORTED') {
      console.log('請求逾時');
    }
    if (error.response?.status === 404) {
      console.log('找不到資源');
    }
  }
}

SSEMessage

來自 Server-Sent Events 串流的一個事件:

interface SSEMessage {
  data: string; // 訊息內容(通常是 JSON 字串)
  event?: string; // 事件類型
  id?: string; // 訊息 ID(用於重連)
  retry?: number; // 重試延遲(毫秒)
}

SSEOptions

sse() 的設定:

interface SSEOptions extends Omit<CustomRequestInit, 'method'> {
  onOpen?: () => void;
  onMessage: (message: SSEMessage) => void;
  onError?: (error: Error) => void;
  onClose?: () => void;
}

SSEConnection

sse() 回傳的控制物件:

interface SSEConnection {
  close(): void;
  readonly readyState: 'connecting' | 'open' | 'closed';
}

7. 授權

MIT License