TypeFetched/README.md
Casey Collier b85b9a63e2 Initial commit: TypedFetch - Zero-dependency, type-safe HTTP client
Features:
- Zero configuration, just works out of the box
- Runtime type inference and validation
- Built-in caching with W-TinyLFU algorithm
- Automatic retries with exponential backoff
- Circuit breaker for resilience
- Request deduplication
- Offline support with queue
- OpenAPI schema discovery
- Full TypeScript support with type descriptors
- Modular architecture
- Configurable for advanced use cases

Built with bun, ready for npm publishing
2025-07-20 12:35:43 -04:00

6.1 KiB

TypedFetch

Fetch for humans who have shit to build

TypedFetch is a next-generation HTTP client that brings type safety, intelligent error handling, and developer-friendly features to API communication. It eliminates the boilerplate and pain points of traditional fetch/axios approaches while providing a tRPC-like experience that works with any REST API.

🚀 Quick Start

npm install typedfetch
import { createTypedFetch } from 'typedfetch'

// Define your API structure
const client = createTypedFetch<{
  users: {
    get: (id: string) => User
    list: () => User[]
    create: (data: CreateUser) => User
  }
}>({
  baseURL: 'https://api.example.com'
})

// Use with full type safety
const { data, error } = await client.users.get('123')
if (error) {
  // TypeScript knows the error structure!
  switch (error.type) {
    case 'not_found': // Handle 404
    case 'network': // Handle network error
  }
}
// TypeScript knows data is User | undefined

Features

🔒 Type Safety Without Code Generation

  • Full TypeScript inference throughout request/response cycle
  • No more any types or manual casting
  • Compile-time URL validation
  • Response type discrimination

🛡️ Unified Error Handling

  • Categorized, actionable errors (network, HTTP, parsing, timeout, abort)
  • Discriminated unions for type-safe error handling
  • Automatic retry logic with exponential backoff
  • Circuit breaker pattern for failing endpoints

🚀 Zero Boilerplate

  • Define once, use everywhere
  • Intelligent defaults
  • Proxy-based API with dot notation
  • Auto-injected auth tokens

Built-in Resilience

  • Request retry with smart conditions
  • Request deduplication
  • Multi-tier caching (memory + IndexedDB)
  • HTTP cache header respect
  • Offline support

🔧 Developer Experience

  • Setup in <5 minutes
  • IntelliSense for everything
  • Clear, actionable error messages
  • Zero compile step required

📚 Documentation

Basic Usage

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

interface CreateUserData {
  name: string
  email: string
}

const client = createTypedFetch<{
  users: {
    get: (id: string) => User
    list: () => User[]
    create: (data: CreateUserData) => User
    update: (params: { id: string } & Partial<User>) => User
    delete: (id: string) => void
  }
}>({
  baseURL: 'https://api.example.com',
  auth: () => getToken(), // Auto-injected
  timeout: 30000,
  
  // Retry configuration
  retry: {
    attempts: 3,
    delay: (attempt) => Math.min(1000 * Math.pow(2, attempt - 1), 10000),
    condition: (error) => error.retryable
  },
  
  // Cache configuration
  cache: {
    storage: 'both', // memory + IndexedDB
    ttl: {
      'users.list': 300000, // 5 minutes
      'users.get': 3600000, // 1 hour
    }
  }
})

Advanced Configuration

const client = createTypedFetch<API>({
  baseURL: process.env.API_URL,
  
  // Global interceptors
  interceptors: {
    request: [(config) => {
      config.headers.authorization = `Bearer ${getToken()}`
      return config
    }],
    response: [(response) => {
      logMetrics(response)
      return response
    }]
  },
  
  // Request deduplication
  dedupe: {
    window: 1000, // 1 second
    key: (config) => `${config.method}:${config.url}`
  }
})

Error Handling

const { data, error, loading } = await client.users.get('123')

if (error) {
  switch (error.type) {
    case 'http':
      if (error.status === 404) {
        console.log('User not found')
      } else if (error.status >= 500) {
        console.log('Server error - will retry automatically')
      }
      break
    case 'network':
      console.log('Network error:', error.message)
      break
    case 'timeout':
      console.log('Request timed out')
      break
    case 'parse':
      console.log('Invalid response format')
      break
    case 'validation':
      console.log('Response validation failed')
      break
    case 'abort':
      console.log('Request was cancelled')
      break
  }
}

Transforms & Interceptors

import { 
  createDateTransform,
  createCamelCaseTransform,
  createLoggingInterceptor 
} from 'typedfetch'

// Add request/response transforms
client.addRequestTransform(createSnakeCaseTransform())
client.addResponseTransform('users', createDateTransform())
client.addResponseTransform('users', createCamelCaseTransform())

// Add interceptors
const logging = createLoggingInterceptor({ 
  logRequests: true, 
  logResponses: true 
})
client.addRequestInterceptor(logging.request)
client.addResponseInterceptor(logging.response)

🏗️ Architecture

TypedFetch is built with a layered architecture:

  • Layer 0: Core Types & Interfaces
  • Layer 1: Protocol Abstraction (fetch/XHR/Node.js)
  • Layer 2: Request Pipeline (interceptors, transforms)
  • Layer 3: Resilience Core (retry, circuit breaker, deduplication)
  • Layer 4: Cache Management (HTTP headers, LRU, IndexedDB)
  • Layer 5: Developer API (Proxy-based interface)

🎯 Why TypedFetch?

vs Axios

  • Type safety without manual interfaces
  • Built-in retry, caching, deduplication
  • Modern async/await patterns
  • Smaller bundle size (<15KB)

vs tRPC

  • Works with any backend (no server changes needed)
  • REST API compatibility
  • Gradual adoption
  • Framework agnostic

vs React Query/SWR

  • Framework agnostic
  • Built-in HTTP client
  • More control over requests
  • Type-safe error handling

📦 Bundle Size

  • Core: <15KB gzipped
  • Zero runtime dependencies
  • Tree-shakeable modules
  • Works without build step

🌐 Browser Support

  • Modern browsers (ES2020+)
  • Node.js 16+
  • Service Worker support
  • IndexedDB for persistence

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

MIT License - see LICENSE for details.


TypedFetch: Because life's too short for any types and network errors. 🚀