Skip to content
TypeWire

@tahanabavi/typefetch

v2.0.0

A strongly typed TypeScript HTTP client powered by Zod contracts, middleware, retries, mock data, contract testing, CLI tooling, and report generation.

Type Inference

TypeFetch infers endpoint input and output types automatically from Zod schemas.

ts
const user = await api.user.getUser({
path: {
id: '123',
},
})

user is inferred as:

ts
{
id: string
name: string
}

Invalid input fails at compile time when possible and at runtime through Zod validation.


Example:

ts
// api/client.ts
import { ApiClient } from '@tahanabavi/typefetch'
import { contracts } from './contracts'

export const client = new ApiClient(
{
baseUrl: import.meta.env.VITE_API_URL,
tokenProvider: async () => localStorage.getItem('token') ?? '',
},
contracts
)

client.init()

export const api = client.modules

Testing

TypeFetch is designed to be easy to test with mocked fetch.

Example:

ts
global.fetch = vi.fn()

;(fetch as any).mockResolvedValueOnce({
ok: true,
json: async () => ({
id: '1',
name: 'Taha',
}),
})

const user = await api.user.getUser({
path: {
id: '1',
},
})

expect(user.name).toBe('Taha')

Contract-driven API testing can also be run through the TypeFetch CLI (@tahanabavi/typewire-cli).

bash
npx typewire init
npx typewire test --mode schema
npx typewire test --mode mock
npx typewire test --mode live --base-url http://localhost:3000

Generated reports can be exported as Markdown, HTML, or JSON:

bash
npx typewire test --mode full --format markdown,json,html --output ./typefetch-report/report

Recommended test coverage:

  • Request validation

  • Response validation

  • Path parameter handling

  • Query string generation

  • JSON body serialization

  • Header merging

  • Auth token injection

  • Token provider behavior

  • Middleware execution order

  • Retry behavior

  • Timeout and abort behavior

  • Mock mode

  • Response wrappers

  • Error normalization

  • Encryption middleware

  • Instrumentation events (start / success / error)

  • Runtime overrides (mock / error / latency / schema swap)


Backend (NestJS)

The official companion package @tahanabavi/typefetch-nestjs ↗ lets you import the same contracts object on a NestJS backend to bind routes and validate request input and response output against each contract's Zod request/response schemas. One contract, end-to-end type-and-runtime safety — the route can't drift from the client.

Compatible with TypeFetch >= 1.6.0.

Installation

bash
npm i @tahanabavi/typefetch-nestjs @tahanabavi/typefetch zod

Peer dependencies: @nestjs/common, @nestjs/core, rxjs, reflect-metadata, and zod@^4.

Example

ts
import { Controller } from '@nestjs/common'
import {
TypeFetchEndpoint,
ContractInput,
InferRequest,
InferResponse,
} from '@tahanabavi/typefetch-nestjs'
import { contracts } from './contracts'

@Controller()
export class UserController {
@TypeFetchEndpoint(contracts.user.getUser) // GET /users/:id from the contract
async getUser(
@ContractInput() input: InferRequest<typeof contracts.user.getUser>
): Promise<InferResponse<typeof contracts.user.getUser>> {
return { id: input.path.id, name: 'Taha' }
}
}

Core API

ExportPurpose
@TypeFetchEndpoint(contract)Binds the HTTP method and path from the contract and wires request/response validation.
@UseContract(contract)Validation-only decorator for retrofitting existing @Get/@Post routes.
@ContractInput()Injects the full validated, typed input, shaped exactly like what the client passed.
@ContractPath() / @ContractQuery() / @ContractBody() / @ContractHeaders()Inject an individual validated input section.
InferRequest<T> / InferResponse<T>Type helpers for a contract's input and output.
TypeFetchModule.forRoot({ ... })Global options.
getContractEndpoint(ctx)Lets a guard read the contract, e.g. to honor its auth flag.

Query and path strings are auto-coerced to the contract's declared types (numbers, booleans, dates, arrays), mirroring the client's URLSearchParams serialization. Validation failures return a RichError-compatible 400 ({ message, code, errors }), so the client's RichError surfaces field errors directly.

Mirrored features

The backend mirrors TypeFetch's client capabilities:

  • OpenAPI 3.0 / Swagger generation from your contracts (setupContractSwagger, buildOpenApiDocument).

  • Multipart / file-upload validation for bodyType: "form-data" contracts.

  • Response envelope matching the client's setResponseWrapper ({ success, data } / { success, message }).

  • Field-level encryption mirroring encryptionMiddleware — decrypts request fields before validation, encrypts response fields after — byte-compatible via crypto-js/node-forge.

Full documentation lives at @tahanabavi/typefetch-nestjs on GitHub ↗ and on npm ↗.