Skip to content

afoures/http-client

Repository files navigation

http-client

A typesafe and robust HTTP client with schema validation.

Why?

Typesafe by design: Path params, query strings, request bodies, and responses are all typed. Responses are typed per status code β€” with 2xx/4xx/5xx wildcard fallbacks β€” so a 200 body and a 404 body each carry their own type. Schema validation happens at runtime with full TypeScript inference.

Standard Schema compatible: Works with Zod, ArkType, Valibot, or any schema library implementing the Standard Schema spec.

Robust error handling: Typed errors for timeouts, network failures, serialization issues, and unexpected errors. No more guessing what went wrong.

Built-in retry: Configurable retry policies with contextual conditions and exponential backoff support.

Installation

npm install @afoures/http-client
# or
pnpm add @afoures/http-client
# or
yarn add @afoures/http-client
# or
bun add @afoures/http-client
import { Endpoint, http_client } from "@afoures/http-client";
import { z } from "zod";

const api = http_client({
  base_url: "https://api.example.com",
  endpoints: {
    users: {
      list: new Endpoint({
        method: "GET",
        pathname: "/users",
        query: {
          schema: z.object({
            page: z
              .number()
              .transform((n) => String(n))
              .optional(),
            limit: z
              .number()
              .transform((n) => String(n))
              .optional(),
          }),
        },
        responses: {
          200: {
            schema: z.array(z.object({ id: z.string(), name: z.string() })),
            parse: "json",
          },
        },
      }),
      get: new Endpoint({
        method: "GET",
        pathname: "/users/:id",
        responses: {
          200: {
            schema: z.object({ id: z.string(), name: z.string() }),
            parse: "json",
          },
          404: {
            schema: z.object({ message: z.string() }),
            parse: "json",
          },
        },
      }),
      create: new Endpoint({
        method: "POST",
        pathname: "/users",
        body: {
          schema: z.object({ name: z.string(), email: z.string().email() }),
          serialize: "json",
        },
        responses: {
          201: {
            schema: z.object({ id: z.string(), name: z.string() }),
            parse: "json",
          },
        },
      }),
    },
  },
});

// All endpoints are fully typed
const list = await api.users.list({ query: { page: 1, limit: 10 } });
const user = await api.users.get({ params: { id: "123" } });
const created = await api.users.create({ body: { name: "John", email: "john@example.com" } });

Documentation

License

MIT

About

πŸ”Ž typesafe and robust HTTP client

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors