Skip to content

Introduction

Fetcher is a modular HTTP client ecosystem built on the native Fetch API. It provides an Axios-like developer experience with interceptor-powered middleware, TypeScript-first design, and native LLM streaming support -- all published as a pnpm monorepo under the @ahoo-wang/* scope.

Why Fetcher?

The native Fetch API is powerful but bare-bones. Applications need base URL management, timeout handling, request/response interceptors, URL template parameters, and structured error handling. Existing solutions like Axios add significant bundle size and do not leverage the modern Fetch API natively.

Fetcher solves these problems while staying lightweight and modular:

ProblemNative FetchAxiosFetcher
Base URL supportManualBuilt-inBuilt-in (FetcherOptions.baseURL)
Timeout handlingManual AbortControllerBuilt-inBuilt-in with TimeoutCapable
InterceptorsNoneYesYes -- 3-phase pipeline (InterceptorManager)
URL path parametersManualManualBuilt-in {param} and :param styles (UrlTemplateStyle)
SSE/LLM streamingManualNoneNative via side-effect import (@ahoo-wang/fetcher-eventstream)
Declarative API clientsNoneNoneDecorator-based (@ahoo-wang/fetcher-decorator)
Bundle size baseline0 KB (native)~13 KB~4 KB (core only)
TypeScript genericsLimitedGoodFirst-class

Package Ecosystem

Fetcher ships as 12 packages in a single monorepo, each installable independently:

Packagenpm NameDescription
fetcher@ahoo-wang/fetcherCore HTTP client -- the foundation for everything
decorator@ahoo-wang/fetcher-decoratorTypeScript decorators for declarative API services
eventbus@ahoo-wang/fetcher-eventbusEvent bus with serial, parallel, and broadcast implementations
eventstream@ahoo-wang/fetcher-eventstreamSSE and LLM streaming support (side-effect module)
openai@ahoo-wang/fetcher-openaiType-safe OpenAI API client
openapi@ahoo-wang/fetcher-openapiOpenAPI 3.x TypeScript type definitions
generator@ahoo-wang/fetcher-generatorCLI code generator from OpenAPI specs
react@ahoo-wang/fetcher-reactReact Hooks for data fetching
storage@ahoo-wang/fetcher-storageCross-environment storage abstraction
cosec@ahoo-wang/fetcher-cosecCoSec authentication integration
wow@ahoo-wang/fetcher-wowWow DDD/CQRS framework support
viewer@ahoo-wang/fetcher-viewerReact + Ant Design API documentation components

Package Dependency Graph

mermaid
graph TD
    subgraph Foundation["Foundation"]
        style Foundation fill:#161b22,stroke:#30363d,color:#e6edf3
        openapi["@ahoo-wang/fetcher-openapi<br>(standalone types)"]
        fetcher["@ahoo-wang/fetcher<br>(core HTTP client)"]
    end

    subgraph Level1["Level 1 - Direct Dependents"]
        style Level1 fill:#161b22,stroke:#30363d,color:#e6edf3
        decorator["@ahoo-wang/fetcher-decorator"]
        eventbus["@ahoo-wang/fetcher-eventbus"]
        eventstream["@ahoo-wang/fetcher-eventstream"]
    end

    subgraph Level2["Level 2 - Composites"]
        style Level2 fill:#161b22,stroke:#30363d,color:#e6edf3
        openai["@ahoo-wang/fetcher-openai"]
        wow["@ahoo-wang/fetcher-wow"]
        storage["@ahoo-wang/fetcher-storage"]
        cosec["@ahoo-wang/fetcher-cosec"]
    end

    subgraph Level3["Level 3 - Integration"]
        style Level3 fill:#161b22,stroke:#30363d,color:#e6edf3
        generator["@ahoo-wang/fetcher-generator"]
        react["@ahoo-wang/fetcher-react"]
        viewer["@ahoo-wang/fetcher-viewer"]
    end

    fetcher --> decorator
    fetcher --> eventbus
    fetcher --> eventstream
    fetcher --> openai
    fetcher --> wow
    eventbus --> storage
    fetcher --> cosec
    eventbus --> cosec
    storage --> cosec
    fetcher --> react
    eventstream --> react
    eventbus --> react
    storage --> react
    wow --> react
    cosec --> react
    react --> viewer
    fetcher --> generator
    eventstream --> generator
    decorator --> generator
    openapi --> generator
    wow --> generator
    decorator --> openai
    eventstream --> openai
    decorator --> wow
    eventstream --> wow

Modular Design

Each package is independently installable. The core @ahoo-wang/fetcher has zero internal dependencies -- all other packages build on top of it:

mermaid
flowchart TB
    subgraph Core["Core (zero internal deps)"]
        style Core fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        fetcher["@ahoo-wang/fetcher"]
    end

    subgraph Extensions["Extension Packages"]
        style Extensions fill:#161b22,stroke:#30363d,color:#e6edf3
        decorator["@ahoo-wang/fetcher-decorator"]
        eventbus["@ahoo-wang/fetcher-eventbus"]
        eventstream["@ahoo-wang/fetcher-eventstream"]
    end

    subgraph Integrations["Integration Packages"]
        style Integrations fill:#161b22,stroke:#30363d,color:#e6edf3
        react["@ahoo-wang/fetcher-react"]
        viewer["@ahoo-wang/fetcher-viewer"]
        generator["@ahoo-wang/fetcher-generator"]
    end

    fetcher --> Extensions
    Extensions --> Integrations
    fetcher -.->|direct| react
    fetcher -.->|direct| generator

Core Architecture

The request lifecycle flows through a three-phase interceptor pipeline:

mermaid
sequenceDiagram
autonumber

    participant App as Application
    participant F as Fetcher
    participant IM as InterceptorManager
    participant RI as Request Interceptors
    participant FI as FetchInterceptor
    participant RESI as Response Interceptors
    participant EI as Error Interceptors

    App->>F: fetch(url, request)
    F->>F: resolveExchange()
    F->>IM: exchange(fetchExchange)
    IM->>RI: intercept(exchange)
    Note over RI: Body serialization<br>URL resolution
    RI->>FI: intercept(exchange)
    FI->>FI: timeoutFetch(request)
    FI-->>RESI: response received
    IM->>RESI: intercept(exchange)
    Note over RESI: Status validation<br>Custom processing
    RESI-->>IM: exchange complete
    IM-->>F: exchange
    F-->>App: result
    Note over EI: Only runs if<br>error occurs

Core Class Hierarchy

mermaid
classDiagram
    class Fetcher {
        +urlBuilder: UrlBuilder
        +headers: RequestHeaders
        +timeout: number
        +interceptors: InterceptorManager
        +fetch(url, request) Promise~R~
        +get(url, request) Promise~R~
        +post(url, request) Promise~R~
        +exchange(request) Promise~FetchExchange~
    }

    class NamedFetcher {
        +name: string
        +constructor(name, options)
    }

    class InterceptorManager {
        +request: InterceptorRegistry
        +response: InterceptorRegistry
        +error: InterceptorRegistry
        +exchange(exchange) Promise~FetchExchange~
    }

    class FetchExchange {
        +fetcher: Fetcher
        +request: FetchRequest
        +response: Response
        +error: Error
        +attributes: Map
        +extractResult() Promise~R~
    }

    class UrlBuilder {
        +baseURL: string
        +build(url, params) string
    }

    Fetcher <|-- NamedFetcher
    Fetcher *-- InterceptorManager
    Fetcher *-- UrlBuilder
    InterceptorManager --> FetchExchange : processes

Key Features

  • Interceptor Pipeline -- Three-phase (request/response/error) middleware chain with ordered execution. Built-in interceptors handle URL resolution, body serialization, HTTP execution, and status validation.
  • URL Template Parameters -- Supports both URI Template ({id}) and Express-style (:param) path parameter interpolation via UrlTemplateStyle.
  • Named Fetcher Registry -- Manage multiple fetcher instances with different configurations using NamedFetcher and FetcherRegistrar.
  • Declarative API Clients -- Use @api, @get, @post, @path, @query, @body decorators to define type-safe API services without writing boilerplate request code.
  • SSE and LLM Streaming -- Native Server-Sent Events support via side-effect import. Patches Response.prototype with eventStream() and jsonEventStream() methods.
  • Result Extractors -- Configurable response extraction strategies (Json, Text, Blob, Exchange, etc.) via ResultExtractors.
  • TypeScript Strict Mode -- Full generic type support across all packages with strict mode enabled.
  • Tree-Shakeable -- Each package is independently installable. Only import what you use.
GoalPage
Get up and running quicklyQuick Start
Configure Fetcher for your projectConfiguration
Contribute to the projectContributing

Released under the Apache License 2.0.