Skip to content

A lightweight fetching library packed with essential features - retries, interceptors, request deduplication and much more, all while still retaining a similar API surface with regular Fetch.

License

Notifications You must be signed in to change notification settings

zayne-labs/callapi

CallApi - Advanced Fetch Client

CallApi Logo

npm version license downloads per month commit activity Ask DeepWiki Code2Tutorial

A modern fetch wrapper that actually makes HTTP requests enjoyable to work with.

CallApi keeps the familiar fetch API you know, but adds the features you've always wanted: automatic retries, request deduplication, smart response parsing, and proper error handling. No more writing the same boilerplate over and over.

Why CallApi?

Drop-in replacement - Same API as fetch, just better Smart retries - Exponential backoff, custom conditions Request deduplication - No more duplicate API calls Auto response parsing - JSON, text, or binary - it just works Better error handling - Structured errors you can actually use Extensible - Hooks and plugins for custom behavior Tiny - Under 6KB, zero dependencies

Quick Example

import { callApi } from "@zayne-labs/callapi";

// Simple request - response type detected automatically
const { data, error } = await callApi("/api/users");

// Create a configured client
import { createFetchClient } from "@zayne-labs/callapi";

const callBackendApi = createFetchClient({
	baseURL: "https://api.example.com",
	retryAttempts: 2,
	timeout: 10000,
});

const user = await callBackendApi("/users/123");

Key Features

Request Deduplication

Prevent duplicate requests automatically:

// These will share the same request
const req1 = callApi("/api/user");
const req2 = callApi("/api/user"); // Uses result from req1

Smart Response Parsing

No more response.json() everywhere:

// Automatically parsed based on Content-Type
const { data } = await callApi("/api/data"); // JSON
const { data } = await callApi("/api/page"); // HTML text
const { data } = await callApi("/api/image.png"); // Blob

Proper Error Handling

const { data, error } = await callApi("/api/users");

if (error) {
	console.log(error.name); // "HTTPError", "ValidationError", etc.
	console.log(error.message); // Human readable message
	console.log(error.errorData); // Server response data
}

URL Parameters & Query Strings

// Dynamic parameters
await callApi("/users/:id/posts/:postId", {
	params: { id: 123, postId: 456 },
}); // → /users/123/posts/456

// Query parameters
await callApi("/search", {
	query: { q: "javascript", limit: 10 },
}); // → /search?q=javascript&limit=10

Schema Validation

Runtime validation with your favorite library:

import { z } from "zod";
import { defineSchema, createFetchClient } from "@zayne-labs/callapi";

// Client-level validation with route schemas
const callBackendApi = createFetchClient({
	baseURL: "https://api.example.com",
	schema: defineSchema({
		"/users/:id": {
			data: z.object({
				id: z.number(),
				name: z.string(),
				email: z.string(),
			}),
		},
		"/posts": {
			data: z.array(
				z.object({
					id: z.number(),
					title: z.string(),
				})
			),
		},
	}),
});

// Automatically validated based on route (both at runtime and at the type level)
const user = await callBackendApi("/users/123"); // Typed as { id: number, name: string, email: string }
const posts = await callBackendApi("/posts"); // Typed as Array<{ id: number, title: string }>

// Per-request validation
import { callApi } from "@zayne-labs/callapi";

const userSchema = z.object({
	id: z.number(),
	name: z.string(),
});

const { data } = await callApi("/api/user", {
	schema: { data: userSchema }, // Validates response
});
// data is now typed as { id: number, name: string }

Documentation

Full documentation and examples →

Installing CallApi

Through npm (recommended)

# npm
npm install @zayne-labs/callapi

# pnpm
pnpm add @zayne-labs/callapi

Then you can use it by importing it in your JavaScript file.

import { callApi } from "@zayne-labs/callapi";

Using CallApi without npm

You can import callApi directly into JavaScript through a CDN.

To do this, you first need to set your script's type to module, then import callApi.

<script type="module">
	import { callApi } from "https://esm.run/@zayne-labs/callapi";
</script>

<!-- Locked to a specific version -->
<script type="module">
	import { callApi } from "https://esm.run/@zayne-labs/callapi@1.10.3";
</script>

About

A lightweight fetching library packed with essential features - retries, interceptors, request deduplication and much more, all while still retaining a similar API surface with regular Fetch.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Contributors 10

Languages