Universal HTTP fetch library with intelligent parsing, error handling, retry logic, and cross-environment compatibility
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Low-level utility functions for request processing, response type detection, option merging, and hook execution used internally by ofetch and available for custom implementations.
Determines if an HTTP method typically includes a request payload/body.
/**
* Check if HTTP method typically includes a request body
* @param method - HTTP method string (default: "GET")
* @returns True if method typically includes payload (PATCH, POST, PUT, DELETE)
*/
function isPayloadMethod(method?: string): boolean;Usage Examples:
import { isPayloadMethod } from "ofetch";
console.log(isPayloadMethod("GET")); // false
console.log(isPayloadMethod("POST")); // true
console.log(isPayloadMethod("PUT")); // true
console.log(isPayloadMethod("DELETE")); // true
console.log(isPayloadMethod("PATCH")); // true
// Use in custom logic
function prepareRequest(method: string, data: any) {
if (isPayloadMethod(method) && data) {
return { method, body: JSON.stringify(data) };
}
return { method };
}Determines if a value can be safely JSON serialized.
/**
* Check if a value can be JSON serialized
* @param value - Value to check for JSON serializability
* @returns True if value can be safely JSON stringified
*/
function isJSONSerializable(value: any): boolean;Usage Examples:
import { isJSONSerializable } from "ofetch";
// Primitive types
console.log(isJSONSerializable("string")); // true
console.log(isJSONSerializable(123)); // true
console.log(isJSONSerializable(true)); // true
console.log(isJSONSerializable(null)); // true
// Objects and arrays
console.log(isJSONSerializable({ key: "value" })); // true
console.log(isJSONSerializable([1, 2, 3])); // true
// Non-serializable types
console.log(isJSONSerializable(undefined)); // false
console.log(isJSONSerializable(() => {})); // false
console.log(isJSONSerializable(Symbol("test"))); // false
console.log(isJSONSerializable(new ArrayBuffer(8))); // false
// Objects with toJSON method
class CustomClass {
toJSON() { return { serialized: true }; }
}
console.log(isJSONSerializable(new CustomClass())); // true
// Use in request preparation
function prepareBody(data: any) {
if (isJSONSerializable(data)) {
return JSON.stringify(data);
}
return data; // Return as-is for FormData, Buffer, etc.
}Automatically detects the appropriate response type based on Content-Type header.
/**
* Detect response type from Content-Type header
* @param contentType - Content-Type header value
* @returns Appropriate ResponseType for parsing
*/
function detectResponseType(contentType?: string): ResponseType;
type ResponseType = "json" | "text" | "blob" | "arrayBuffer" | "stream";Usage Examples:
import { detectResponseType } from "ofetch";
// JSON content types
console.log(detectResponseType("application/json")); // "json"
console.log(detectResponseType("application/json; charset=utf-8")); // "json"
console.log(detectResponseType("application/ld+json")); // "json"
// Text content types
console.log(detectResponseType("text/plain")); // "text"
console.log(detectResponseType("text/html")); // "text"
console.log(detectResponseType("application/xml")); // "text"
console.log(detectResponseType("image/svg+xml")); // "text"
// Binary content types
console.log(detectResponseType("image/png")); // "blob"
console.log(detectResponseType("application/pdf")); // "blob"
console.log(detectResponseType("video/mp4")); // "blob"
// Default behavior
console.log(detectResponseType("")); // "json"
console.log(detectResponseType(undefined)); // "json"
// Use in custom response handling
async function handleResponse(response: Response) {
const contentType = response.headers.get("content-type") || "";
const responseType = detectResponseType(contentType);
switch (responseType) {
case "json":
return await response.json();
case "text":
return await response.text();
case "blob":
return await response.blob();
default:
return await response.text();
}
}Merges fetch options with defaults, handling headers and query parameters properly.
/**
* Resolve and merge fetch options with defaults
* @param request - The fetch request (URL or Request object)
* @param input - Input fetch options
* @param defaults - Default fetch options
* @param Headers - Headers constructor
* @returns Merged and resolved fetch options
*/
function resolveFetchOptions<R extends ResponseType = ResponseType, T = any>(
request: FetchRequest,
input: FetchOptions<R, T> | undefined,
defaults: FetchOptions<R, T> | undefined,
Headers: typeof globalThis.Headers
): ResolvedFetchOptions<R, T>;Usage Examples:
import { resolveFetchOptions } from "ofetch";
// Merge options with defaults
const defaults = {
headers: { "Content-Type": "application/json" },
timeout: 5000,
query: { version: "v1" }
};
const input = {
headers: { "Authorization": "Bearer token" },
query: { filter: "active" }
};
const resolved = resolveFetchOptions(
"https://api.example.com/users",
input,
defaults,
Headers
);
console.log(resolved.headers.get("Content-Type")); // "application/json"
console.log(resolved.headers.get("Authorization")); // "Bearer token"
console.log(resolved.query); // { version: "v1", filter: "active" }
console.log(resolved.timeout); // 5000
// Use in custom fetch implementation
function customFetch(url: string, options?: any) {
const resolved = resolveFetchOptions(url, options, myDefaults, Headers);
return fetch(url, resolved);
}Executes interceptor hooks in sequence, supporting both single hooks and arrays.
/**
* Execute fetch hooks in sequence
* @param context - Fetch context containing request, options, response, error
* @param hooks - Single hook function or array of hook functions
* @returns Promise that resolves when all hooks complete
*/
async function callHooks<C extends FetchContext = FetchContext>(
context: C,
hooks: FetchHook<C> | FetchHook<C>[] | undefined
): Promise<void>;
type FetchHook<C extends FetchContext = FetchContext> = (
context: C
) => MaybePromise<void>;
type MaybePromise<T> = T | Promise<T>;Usage Examples:
import { callHooks } from "ofetch";
// Single hook
const singleHook = ({ options }: FetchContext) => {
options.headers.set("X-Custom", "value");
};
// Multiple hooks
const hooks = [
({ options }: FetchContext) => {
console.log("Hook 1");
options.headers.set("X-Hook1", "executed");
},
async ({ options }: FetchContext) => {
console.log("Hook 2");
const token = await getAuthToken();
options.headers.set("Authorization", `Bearer ${token}`);
}
];
// Execute hooks
const context = {
request: "https://api.example.com/data",
options: { headers: new Headers() },
response: undefined,
error: undefined
};
await callHooks(context, singleHook);
await callHooks(context, hooks);
// Use in custom interceptor system
class CustomFetcher {
private onRequestHooks: FetchHook[] = [];
addHook(hook: FetchHook) {
this.onRequestHooks.push(hook);
}
async fetch(url: string, options: any = {}) {
const context = { request: url, options: { ...options, headers: new Headers(options.headers) } };
// Execute all hooks
await callHooks(context, this.onRequestHooks);
return fetch(context.request, context.options);
}
}Creates a Node.js-optimized fetch function with optional keep-alive support.
/**
* Create Node.js-specific fetch with keep-alive support
* Uses FETCH_KEEP_ALIVE environment variable to enable persistent connections
* @returns Fetch function with Node.js optimizations
*/
function createNodeFetch(): typeof globalThis.fetch;Usage Examples:
import { createNodeFetch } from "ofetch/node";
// Enable keep-alive via environment variable
process.env.FETCH_KEEP_ALIVE = "true";
const fetch = createNodeFetch();
// Use the Node.js optimized fetch
const response = await fetch("https://api.example.com/data");
// Without keep-alive (default)
process.env.FETCH_KEEP_ALIVE = "false";
const standardFetch = createNodeFetch();
// Use in custom ofetch instance
import { createFetch } from "ofetch";
const nodeFetch = createFetch({
fetch: createNodeFetch(),
defaults: { timeout: 10000 }
});The utilities module also defines several internal constants used for request processing:
// HTTP methods that typically include request payloads
const payloadMethods = ["PATCH", "POST", "PUT", "DELETE"];
// Content types that should be parsed as text
const textTypes = [
"image/svg",
"application/xml",
"application/xhtml",
"application/html"
];
// Regular expression for JSON content type detection
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;These constants help ensure consistent behavior across different response types and request methods.
Install with Tessl CLI
npx tessl i tessl/npm-ofetch