Type Helpers

Advanced type helpers for CallApi

CallApi provides type helpers for complex type scenarios and better type safety.

CallApi Context Types

Scoped Metadata

Register metadata for one callApi instance with metaHelper<TMeta>() from @zayne-labs/callapi/utils:

import { createFetchClient } from "@zayne-labs/callapi";
import { metaHelper } from "@zayne-labs/callapi/utils";

const callApi = createFetchClient({
	meta: metaHelper<{ requestId?: string }>(),
});

await callApi("/users", { meta: { requestId: "req-1" } });

The helper returns undefined; it registers a type, not default metadata. A plain base meta object supplies runtime values without registering its inferred shape.

Plugin Context

Put Meta and InferredExtraOptions in the context when the plugin's hooks need to read them. A callApi instance using the plugin can pass those values too. Data and ErrorData only affect the plugin's hooks:

import type { GetCallApiContext } from "@zayne-labs/callapi";
import { definePluginWithContext } from "@zayne-labs/callapi/utils";

type AuditContext = GetCallApiContext<{
	InferredExtraOptions: { auditLabel?: string };
	Meta: { audit?: { actor: string } };
}>;

const auditPlugin = definePluginWithContext<AuditContext>()({
	id: "audit",
	name: "Audit",
	hooks: {
		onRequest: ({ options }) => {
			console.info(options.meta?.audit?.actor);
			console.info(options.auditLabel);
		},
	},
});

Use createFetchClientWithContext for full context on one callApi instance, or Register to apply types globally.

GetCallApiContext

Provides type safety and IntelliSense when defining context types:

custom-context.ts
import type { GetCallApiContext } from "@zayne-labs/callapi";

type MyAppContext = GetCallApiContext<{
	Data: {
		email: string;
		id: number;
		name: string;
	};
	ErrorData: {
		code: string;
		details?: Record<string, any>;
		message: string;
	};
	Meta: {
		feature?: string;
		requestId: string;
		userId: string;
	};
	ResultMode: "all";
}>;

// Use with createFetchClientWithContext
const createAppClient = createFetchClientWithContext<MyAppContext>();

Benefits: validates context structure at compile time, provides autocomplete, and catches typos.

createFetchClientWithContext

Create a callApi instance with custom context types:

typed-client.ts
import { createFetchClientWithContext, GetCallApiContext } from "@zayne-labs/callapi";

type AppContext = GetCallApiContext<{
	Data: { id: number; name: string };
	ErrorData: { code: string; message: string };
	Meta: { requestId: string; userId: string };
}>;

const callBackendApi = createFetchClientWithContext<AppContext>()({
	baseURL: "https://api.example.com",
	meta: {
		userId: "123", // Fully typed based on AppContext.Meta
		requestId: "req-456",
	},
});

const { data } = await callBackendApi("/users/1");
// data is typed as AppContext.Data: { id: number; name: string }

Global Meta Registration

Register global meta types using module augmentation:

types/callapi.d.ts
declare module "@zayne-labs/callapi" {
	interface Register {
		meta: {
			feature?: string;
			priority?: "high" | "low" | "normal";
			requestId?: string;
			source?: "background" | "system" | "user-action";
			userId?: string;
		};
	}
}

Hook Context Types

Each hook has a corresponding context type:

hook-types.ts
import type { ErrorContext, RequestContext, SuccessContext } from "@zayne-labs/callapi";

function createLoggingHooks<TData, TErrorData>() {
	return {
		onRequest: (ctx: RequestContext) => {
			console.log(`Request: ${ctx.options.initURL}`);
		},

		onSuccess: (ctx: SuccessContext<{ Data: TData }>) => {
			console.log(`Success: ${ctx.data}`);
		},

		onError: (ctx: ErrorContext<{ ErrorData: TErrorData }>) => {
			console.log(`Error: ${ctx.error.message}`);
		},
	};
}

Plugin Types

CallApiPlugin

Use extraOptionsHelper<T>() with definePlugin to add request options to callApi instances using the plugin. It doesn't make those options available inside the plugin's hooks:

plugin-types.ts
import { definePlugin, extraOptionsHelper } from "@zayne-labs/callapi/utils";

type MyPluginOptions = {
	apiKey: string;
	debug?: boolean;
};

const myPlugin = definePlugin({
	id: "my-plugin",
	name: "My Plugin",
	extraOptionsDef: extraOptionsHelper<MyPluginOptions>(),
});

If the plugin's hooks also need those types, put InferredExtraOptions in the context passed to definePluginWithContext. If both the context and a helper define the same field, their types combine.

These type utilities provide advanced TypeScript support while maintaining type safety throughout your application.

Edit on GitHub

Last updated on

On this page