### Install and Run Development Server Source: https://github.com/better-auth/better-fetch/blob/main/doc/README.md Use these commands to install dependencies and start the development server. ```bash pnpm install pnpm dev ``` -------------------------------- ### Install Project Dependencies with Bun Source: https://github.com/better-auth/better-fetch/blob/main/dev/README.md Use this command to install all necessary packages for the project. Ensure Bun is installed. ```bash bun install ``` -------------------------------- ### Run the Project with Bun Source: https://github.com/better-auth/better-fetch/blob/main/dev/README.md Execute the main project file using the Bun runtime. This command starts the application. ```bash bun run index.ts ``` -------------------------------- ### Install Logger Plugin Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/utility/logger.mdx Install the logger plugin using npm. ```bash npm i @better-fetch/logger ``` -------------------------------- ### Initialize Fetch with Logger Plugin Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/utility/logger.mdx Basic setup for Better Fetch with the logger plugin enabled. ```typescript import { createFetch } from "@better-fetch/fetch"; import { logger } from "@better-fetch/logger"; const $fetch = createFetch({ baseURL: "http://localhost:3000", plugins: [ logger(), ], }); ``` -------------------------------- ### Install Better Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Install the core Better Fetch package using npm. ```bash npm i @better-fetch/fetch ``` -------------------------------- ### Create Fetch Instance with Hooks Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/hooks.mdx Initializes a fetch instance with various hooks defined. This example shows the basic structure for all hooks. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", onRequest(context) { return context; }, onResponse(context) { return context.response }, onError(context) { }, onSuccess(context) { }, }) ``` -------------------------------- ### Install a Schema Validator Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Install a Standard Schema compliant validator like Zod if you plan to use runtime validation. ```bash npm i zod # valibot, arktype... ``` -------------------------------- ### Header Aggregation Example Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Demonstrates how configuration, schema, and request headers are merged. Configuration headers are applied first, followed by schema headers, and finally request headers, with later headers overriding earlier ones. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "http://localhost:3000", headers: { "x-api-key": "config-key", // Applied to all requests }, schema: createSchema({ "/api/data": { headers: z.object({ "x-tenant-id": z.string(), }), }, }), }) // Final headers will include: x-api-key, x-tenant-id, and x-request-id const { data } = await $fetch("/api/data", { headers: { "x-tenant-id": "tenant-123", "x-request-id": "req-456", // Additional header }, }) ``` -------------------------------- ### Initialize Plugin for URL Modification Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/plugins.mdx Use the `init` function within a plugin to modify the request URL before it's sent. This example redirects HTTP requests to a local development server. ```ts import { createFetch, BetterFetchPlugin } from "@better-fetch/fetch"; const myPlugin = { id: "my-plugin", name: "My Plugin", init: async (url, options) => { if(url.startsWith("http://")) { const _url = new URL(url) const DEV_URL = "http://localhost:3000" return { url: `${DEV_URL}/${_url.pathname}`, options, } } return { url, options, } }, } satisfies BetterFetchPlugin; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", plugins: [myPlugin], }); ``` -------------------------------- ### Enforcing Strict Schema Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Use the `strict: true` option when creating the schema to enforce that only defined paths and keys are allowed. This example demonstrates setting up a fetch instance with a schema and attempting to call an invalid path, which would result in an error if strict mode is enabled. ```ts import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: createSchema({ "/path": { output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), }, }, { strict: true }), }) // @errors: 2345 const { data, error } = await $fetch("/invalid-path") ``` -------------------------------- ### Plugin with Schema Validation Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/plugins.mdx Define a schema for a plugin using `createSchema` to validate request inputs and outputs. This example uses Zod for schema definition and validation. ```ts import { createFetch, createSchema, BetterFetchPlugin } from "@better-fetch/fetch"; // Example using zod (or any Standard Schema compliant validator) import { z } from "zod"; // @errors: 2353 2561 const plugin = { id: "my-plugin", name: "My Plugin", schema: createSchema({ "/path": { input: z.object({ /** * You can write descriptions for the properties. Hover over the property to see * the description. */ userId: z.string(), /** * The id property is required */ id: z.number(), }), output: z.object({ title: z.string(), completed: z.boolean(), }), } },{ baseURL: "https://jsonplaceholder.typicode.com", }) } satisfies BetterFetchPlugin; const $fetch = createFetch({ baseURL: "localhost:3000" }) const { data, error } = await $fetch("https://jsonplaceholder.typicode.com/path", { body: { userId: "1", id: 1, title: "title", completed: true, }, }); //@annotate: baseURL is inferred to "https://jsonplaceholder.typicode.com" ``` -------------------------------- ### Create Custom Fetch Instance Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Create a reusable fetch instance with custom configurations like `baseURL` and retry logic using `createFetch`. ```ts import { createFetch } from "@better-fetch/fetch"; export const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", retry: { type: "linear", attempts: 3, delay: 1000 } }); const { data, error } = await $fetch<{ userId: number; id: number; title: string; completed: boolean; }>("/todos/1"); ``` -------------------------------- ### Plugin for Custom Options with Upload Progress Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/plugins.mdx Use the `getOptions` function in a plugin to define custom options, such as upload progress callbacks. This allows passing non-standard options to the fetch function. ```ts import { createFetch, createSchema, BetterFetchPlugin } from "@better-fetch/fetch"; import { z } from "zod"; const plugin = { id: "my-plugin", name: "My Plugin", getOptions() { return z.object({ onUploadProgress: z.function().args(z.object({ loaded: z.number(), total: z.number(), })), }); }, } satisfies BetterFetchPlugin; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", plugins: [plugin], }); const { data, error } = await $fetch("https://jsonplaceholder.typicode.com/path", { onUploadProgress({ loaded, total, }) { console.log(`Uploaded ${loaded} of ${total} bytes`); }, }); ``` -------------------------------- ### Dynamic Path Parameters with Better Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Demonstrates defining dynamic path parameters using string modifiers and the 'params' key in Better Fetch schemas. Handles single and multiple dynamic parameters. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const schema = createSchema({ "/user/:id": { output: z.object({ name: z.string(), }), }, "/post": { params: z.object({ id: z.string(), title: z.string(), }), }, "/post/:id/:title": { output: z.object({ title: z.string(), }), } }) const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: schema }) const response1 = await $fetch("/user/:id", { params: { id: "1", } }) const response2 = await $fetch("/post", { params: { id: "1", title: "title" }, }) const response3 = await $fetch("/post/:id/:title", { params: { id: "1", title: "title" } }) ``` -------------------------------- ### Create Fetch Schema with Zod Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Import `createSchema` and `createFetch` from `@better-fetch/fetch`. Define your API schema using Zod for input and output validation. Pass the created schema to `createFetch`. ```typescript import { createSchema, createFetch } from "@better-fetch/fetch"; import { z } from "zod"; export const schema = createSchema({ "/path": { input: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), } }) const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: schema }); ``` -------------------------------- ### Configuration Level Headers Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Set headers that apply to all requests by providing them in the createFetch configuration. This is useful for API keys or client versions. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", headers: { "x-api-key": "my-api-key", "x-client-version": "1.0.0", }, }) ``` -------------------------------- ### Define and Use Dynamic Parameters Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/dynamic-parameters.mdx Define dynamic parameters in your API paths using the ':' prefix. These parameters are then replaced with the corresponding values provided in the `params` option when making a request. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) const res = await $fetch("/path/:id", { params: { id: "1" } }) const res2 = await $fetch("/repos/:owner/:repo", { params: { owner: "octocat", repo: "hello-world" } }) ``` -------------------------------- ### Configure Logger Log Format Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/utility/logger.mdx Set the log format to 'legacy' for compatibility with older versions. ```typescript import { createFetch } from "@better-fetch/fetch"; import { logger } from "@better-fetch/logger"; const $fetch = createFetch({ baseURL: "http://localhost:3000", plugins: [ logger({ logFormat: "legacy", }), ], }); ``` -------------------------------- ### Throwing Errors with Better Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/handling-errors.mdx Illustrates how to configure Better Fetch to throw errors instead of returning them as values. This simplifies the success path by only returning data. ```typescript import { betterFetch } from '@better-fetch/fetch'; import { z } from 'zod'; const data = await betterFetch("https://jsonplaceholder.typicode.com/todos/1", { throw: true, // [!code highlight] output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), }); ``` -------------------------------- ### Custom Fetch Instance with Throw Option Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/handling-errors.mdx Creates a custom fetch instance using `createFetch` with the `throw: true` option. This ensures all requests made with this instance will throw errors. ```typescript import { createFetch } from "@better-fetch/fetch"; export const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", retry: 2, throw: true, }); const data = await $fetch<{ userId: number; id: number; title: string; completed: boolean; }>("/todos/1"); ``` -------------------------------- ### Case-Insensitive Header Handling Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Illustrates Better Fetch's automatic handling of case-insensitive HTTP headers. It shows that headers can be provided in various casing conventions and will be correctly processed. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ schema: createSchema({ "/api/users": { headers: z.object({ "x-custom-header": z.string(), // Define in lowercase }), }, }), }) // All of these will work correctly: await $fetch("/api/users", { headers: { "x-custom-header": "value" }, }) await $fetch("/api/users", { headers: { "X-Custom-Header": "value" }, }) await $fetch("/api/users", { headers: { "X-CUSTOM-HEADER": "value" }, }) ``` -------------------------------- ### Fetch with Optional Headers in Schema Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Shows how to define optional headers within a Better Fetch schema using Zod's `.optional()` modifier. This allows requests to succeed even if the optional header is omitted. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ schema: createSchema({ "/api/users": { headers: z.object({ "x-user-id": z.string(), "x-trace-id": z.string().optional(), // Optional header }), }, }), }) // This works without x-trace-id await $fetch("/api/users", { headers: { "x-user-id": "user-123", }, }) ``` -------------------------------- ### Basic Retry with Attempts Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Perform a request with a specified number of retry attempts. This is a simple way to handle temporary failures. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) // ---cut--- const res = await $fetch("https://jsonplaceholder.typicode.com/todos/1", { retry: 3 }); ``` -------------------------------- ### Set Version Headers Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Set a global version header and define request-specific headers using Zod schemas for validation. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://api.example.com", headers: { "x-api-version": "2024-01-01", }, schema: createSchema({ "/api/v2/users": { headers: z.object({ "x-client-version": z.string(), }), }, }), }) ``` -------------------------------- ### Set API Key Header Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Configure a global API key header for all requests. Ensure the API_KEY environment variable is set. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "https://api.example.com", headers: { "x-api-key": process.env.API_KEY || "", }, }) ``` -------------------------------- ### Basic Authorization Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/authorization.mdx Add basic authentication to the request. The username and password are added to the Authorization header. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", auth: { type: "Basic", username: "my-username", password: "my-password", }, }) ``` -------------------------------- ### Retry with Callback Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Execute a callback function after each retry attempt. Useful for logging retry events or performing side effects. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) // ---cut--- const res = await $fetch("https://jsonplaceholder.typicode.com/todos/1", { retry: 3, onRetry: (response) => { console.log(`Retrying request.`); } }); ``` -------------------------------- ### Inferring Response with Generics and Throw Option (False) Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/handling-errors.mdx Demonstrates how to correctly infer the response type when using generics and the `throw` option by explicitly passing `false` as the second generic argument. ```typescript import { betterFetch } from '@better-fetch/fetch'; import { z } from 'zod'; const data = await betterFetch<{ userId: number; id: number; title: string; completed: boolean; }, false // [!code highlight] >("https://jsonplaceholder.typicode.com/todos/1"); ``` -------------------------------- ### Fetch with Schema Validation for Headers Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Demonstrates how Better Fetch validates request headers against a Zod schema. If headers do not match the schema (e.g., incorrect UUID format), a detailed validation error is thrown. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ schema: createSchema({ "/api/users": { headers: z.object({ "x-user-id": z.string().uuid(), }), }, }), }) try { await $fetch("/api/users", { headers: { "x-user-id": "invalid-uuid", // Will fail validation }, }) } catch (error) { console.error(error.message) // Error: [ // { // "code": "invalid_string", // "validation": "uuid", // "path": ["x-user-id"], // "message": "Invalid uuid" // } // ] } ``` -------------------------------- ### Enable Verbose Logging Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/utility/logger.mdx Enable verbose mode for the logger plugin to capture more detailed request information. ```typescript import { createFetch } from "@better-fetch/fetch"; import { logger } from "@better-fetch/logger"; const $fetch = createFetch({ baseURL: "http://localhost:3000", plugins: [ logger({ verbose: true, }), ], }); ``` -------------------------------- ### Implement Request Tracing Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Add a request ID header for tracing if it's not already present. Requires the 'uuid' package. ```typescript import { createFetch } from "@better-fetch/fetch"; import { v4 as uuidv4 } from "uuid"; const $fetch = createFetch({ baseURL: "https://api.example.com", onRequest(context) { if (!context.headers.has("x-request-id")) { context.headers.set("x-request-id", uuidv4()); } }, }) ``` -------------------------------- ### Configure Logger Enabled Option Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/utility/logger.mdx Conditionally enable the logger based on the environment, typically for development. ```typescript import { createFetch } from "@better-fetch/fetch"; import { logger } from "@better-fetch/logger"; const $fetch = createFetch({ baseURL: "http://localhost:3000", plugins: [ logger({ enabled: process.env.NODE_ENV === "development", }), ], }); ``` -------------------------------- ### Fetch with Throwing Errors Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Configure a fetch instance to throw errors instead of returning them in the `error` property by setting the `throw` option to `true`. ```ts import { createFetch } from '@better-fetch/fetch'; import { z } from 'zod'; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", throw: true, }); const data = await $fetch<{ userId: number; }>("https://jsonplaceholder.typicode.com/todos/1"); ``` -------------------------------- ### Configure Custom Console for Logger Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/utility/logger.mdx Provide a custom console object to the logger plugin for alternative logging implementations. ```typescript import { createFetch } from "@better-fetch/fetch"; import { logger } from "@better-fetch/logger"; const $fetch = createFetch({ baseURL: "http://localhost:3000", plugins: [ logger({ console: { log: (...args) => console.log(...args), error: (...args) => console.error(...args), warn: (...args) => console.warn(...args), }, }), ], }); ``` -------------------------------- ### Plugin with Lifecycle Hooks Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/plugins.mdx Implement `onRequest`, `onResponse`, `onError`, and `onSuccess` hooks in a plugin to intercept and modify the request lifecycle. Hooks are called in the order plugins are registered. ```ts import { createFetch, BetterFetchPlugin } from "@better-fetch/fetch"; const myPlugin = { id: "my-plugin", name: "My Plugin", hooks: { onRequest(context) { // do something with the context return context; }, onResponse(context) { // do something with the context return context; }, onError(context) { // do something with the context }, onSuccess(context) { // do something with the context }, } } satisfies BetterFetchPlugin; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", plugins: [myPlugin], }); ``` -------------------------------- ### Basic Fetch with Generic Type Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Make a request using `betterFetch` and define the expected response data structure using TypeScript generics. ```ts import { betterFetch } from '@better-fetch/fetch'; // Using generic type const { data, error } = await betterFetch<{ userId: string; id: number; title: string; completed: boolean; }>("https://jsonplaceholder.typicode.com/todos/1"); ``` -------------------------------- ### Exponential Backoff Strategy Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Configure exponential backoff for retries, where the delay doubles with each attempt, capped at a maximum delay. This prevents overwhelming a service during high load. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) // ---cut--- const res = await $fetch("https://jsonplaceholder.typicode.com/todos/1", { retry: { count: 3, interval: 1000, //optional type: "exponential", attempts: 5, baseDelay: 1000, // Start with 1 second delay maxDelay: 10000 // Cap the delay at 10 seconds, so requests would go out after 1s then 2s, 4s, 8s, 10s } }); ``` -------------------------------- ### Define Fetch Schema with Zod Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Define a fetch schema using Zod to specify input and output structures for a specific API path. This schema is then used to configure a custom fetch instance. ```ts import { createSchema, createFetch } from "@better-fetch/fetch"; // ZOD example import { z } from "zod"; export const zodSchema = createSchema({ "/path": { input: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), } }) const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: zodSchema }); const { data, error } = await $fetch("/path", { body: { userId: "1", id: 1, title: "title", completed: true, }, }); ``` -------------------------------- ### Linear Retry Strategy Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Implement a linear backoff strategy for retries, where the delay between attempts increases by a fixed amount. Useful for predictable retry intervals. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) // ---cut--- const res = await $fetch("https://jsonplaceholder.typicode.com/todos/1", { retry: { type: "linear", attempts: 3, delay: 1000 // 1 second delay between each attempt } }); ``` -------------------------------- ### Define Output Schema for Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Defines an output schema for a fetch request. If an output schema is defined, the response body will be parsed according to this schema. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: createSchema({ "/path": { output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), }, }), }) const { data, error } = await $fetch("/path") // @annotate: Hover over the data object to see the type ``` -------------------------------- ### Fetch with Zod Schema Validation Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/getting-started.mdx Make a request using `betterFetch` and provide a Zod schema to validate the response data. Ensure `strict` mode is enabled in tsconfig. ```ts import { betterFetch } from '@better-fetch/fetch'; // Using a Standard Schema validator (for example, zod) import { z } from 'zod'; // or your preferred Standard Schema compliant library const { data: todos, error: todoError } = await betterFetch("https://jsonplaceholder.typicode.com/todos/1", { output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }) }); // @annotate: Hover over the data object to see the type ``` -------------------------------- ### Method Modifiers with Better Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Shows how to explicitly define HTTP methods (e.g., PUT) for API requests using method modifiers prepended to the path in Better Fetch schemas. The request is made to the base path without the modifier. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: createSchema({ "@put/user": { // [!code highlight] input: z.object({ title: z.string(), completed: z.boolean(), }), output: z.object({ title: z.string(), completed: z.boolean(), }), }, }), }) const { data, error } = await $fetch("/@put/user", { body: { title: "title", completed: true, } }) // @annotate: the request will be made to "/user" path with a PUT method. ``` -------------------------------- ### Define Input Schema for Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Defines an input schema for a fetch request. If an input schema is defined, the request will use the POST method and require a body. Wrap with z.optional to make the body optional. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: createSchema({ "/path": { input: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), }, }), }) // @errors: 2739 const { data, error } = await $fetch("/path", { body: {} }) ``` -------------------------------- ### Request Level Headers Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Set headers for individual requests by including them in the options object of the betterFetch call. This allows for request-specific headers like unique request IDs. ```typescript import { betterFetch } from "@better-fetch/fetch"; const { data, error } = await betterFetch("http://localhost:3000/api/users", { headers: { "x-request-id": "unique-request-id", }, }) ``` -------------------------------- ### Customize Default Output Type Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/default-types.mdx Set a custom default output type using the `defaultOutput` option in `createFetch`. This type is used when no specific output schema is provided for a request. It does not perform validation. ```typescript import { createFetch } from "@better-fetch/fetch"; // Example using zod (or any Standard Schema compliant library) import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", defaultOutput: z.any(), }) const { data, error } = await $fetch("/todos/1") // @annotate: Hover over the data object to see the type ``` -------------------------------- ### Set Request Timeout Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Configure a default timeout for all requests or override it for specific requests. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", timeout: 5000, }) // ---cut--- const res = await $fetch("/api/users", { timeout: 10000, }); ``` -------------------------------- ### Type-Safe Headers with Zod Schema Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Illustrates how defining headers in a Zod schema provides type inference for header values. TypeScript can then ensure that provided header values conform to the expected types or enums. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ schema: createSchema({ "/api/users": { headers: z.object({ "x-user-id": z.string(), "x-role": z.enum(["admin", "user"]), }), }, }), }) await $fetch("/api/users", { headers: { "x-user-id": "123", "x-role": "admin", // TypeScript knows the valid values }, }) ``` -------------------------------- ### Define Headers Schema for Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Defines a headers schema for a fetch request. This allows for validation of request headers. Header keys should be in lowercase for case-insensitive matching. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "http://localhost:3000", schema: createSchema({ "/api/users": { headers: z.object({ "x-api-key": z.string(), "x-user-id": z.string().uuid(), }), }, }), }) const { data } = await $fetch("/api/users", { headers: { "x-api-key": "my-key", "x-user-id": "123e4567-e89b-12d3-a456-426614174000", }, }) ``` -------------------------------- ### Configure Auto Retry Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Set a default number of retry attempts for requests. This is useful for handling transient network issues. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) // ---cut--- const res = await $fetch("/api/users", { retry: 3 }); ``` -------------------------------- ### Define Query Schema for Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/fetch-schema.mdx Defines a query schema for a fetch request. If a query schema is defined, the provided data will be appended to the URL as query parameters. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", schema: createSchema({ "/path": { query: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), }, }), }) // @errors: 2739 const { data, error } = await $fetch("/path", { query: {} }) // @annotate: Hover over the data object to see the type ``` -------------------------------- ### Default Error Handling in Better Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/handling-errors.mdx Demonstrates the default behavior where Better Fetch returns errors as a value. The error object includes status, statusText, and a potentially parsed message. ```typescript import { betterFetch } from '@better-fetch/fetch'; import { z } from 'zod'; const { error } = await betterFetch("https://jsonplaceholder.typicode.com/todos/1"); // @annotate: Hover over the error object to see the type ``` -------------------------------- ### Process Response with onResponse Hook Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/hooks.mdx The onResponse hook is executed when a response is received. It receives the response context and should return the processed response. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", onResponse(context) { // do something with the context return context.response // return the response }, }) ``` -------------------------------- ### Custom Error Type with Better Fetch Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/handling-errors.mdx Shows how to define and use a custom error type with Better Fetch by passing it as a generic argument. This allows for more specific error structures. ```typescript import { betterFetch } from 'better-fetch'; const { error } = await betterFetch<{ id: number; userId: string; title: string; completed: boolean; }, { message?: string; // [!code highlight] error?: string;// [!code highlight] }>("https://jsonplaceholder.typicode.com/todos/1"); ``` -------------------------------- ### Handle Success and Error with Hooks Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/hooks.mdx The onSuccess and onError hooks are called upon successful requests or errors, respectively. They receive the context but are not expected to return anything. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", onSuccess(context) { // do something with the context }, onError(context) { // do something with the context }, }) ``` -------------------------------- ### Schema-Based Header Validation Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/headers.mdx Define header schemas using Zod for runtime validation and type inference. Header keys in schemas should be lowercase for case-insensitive matching. ```typescript import { createFetch, createSchema } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "http://localhost:3000", schema: createSchema({ "/api/users": { headers: z.object({ "x-user-id": z.string().uuid(), "x-api-version": z.string().regex(/^\d+\.\d+\.\d+$/), }), }, }), }) // This will validate headers at runtime const { data, error } = await $fetch("/api/users", { headers: { "x-user-id": "123e4567-e89b-12d3-a456-426614174000", "x-api-version": "1.0.0", }, }) ``` -------------------------------- ### Bearer Token Authorization with Function Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/authorization.mdx Pass a function that returns a bearer token. The function will be called only once when the request is made. If it returns undefined, the header will not be added to the request. ```typescript import { createFetch } from "@better-fetch/fetch"; const authStore = { getToken: () => "my-token", } //---cut--- const $fetch = createFetch({ baseURL: "http://localhost:3000", auth: { type: "Bearer", token: () => authStore.getToken(), }, }) ``` -------------------------------- ### Override Default Output with Specific Schema Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/default-types.mdx When an `output` schema is provided in the request options, it overrides the `defaultOutput` type. This allows for strongly typed responses on a per-request basis. ```typescript import { createFetch } from "@better-fetch/fetch"; import { z } from "zod"; const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", defaultOutput: z.any(), }); const { data, error } = await $fetch("/todos/1", { output: z.object({ userId: z.string(), id: z.number(), title: z.string(), completed: z.boolean(), }), }) // @annotate: Hover over the data object to see the type ``` -------------------------------- ### Bearer Token Authorization Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/authorization.mdx Add a bearer token to the request. The token is added to the Authorization header. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", auth: { type: "Bearer", token: "my-token", }, }) ``` -------------------------------- ### Modify Request Headers with onRequest Hook Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/hooks.mdx The onRequest hook is called before a request is sent. Use it to modify headers, add authentication, or log requests. It expects the modified context to be returned. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", onRequest(context) { // Add or modify headers context.headers.set("x-request-time", new Date().toISOString()); return context; }, }) ``` -------------------------------- ### Customize Default Error Type Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/default-types.mdx Configure a custom default error type using the `defaultError` option in `createFetch`. This custom type extends the default error properties (`status`, `statusText`) and is merged with JSON error responses. ```typescript import { createFetch } from "@better-fetch/fetch"; import { z } from "zod"; // Example only const $fetch = createFetch({ baseURL: "https://jsonplaceholder.typicode.com", defaultError: z.object({ message: z.string().optional(), error: z.string(), }), }) const { data, error } = await $fetch("/todos/1") // @annotate: Hover over the error object to see the type ``` -------------------------------- ### Custom Retry Condition Source: https://github.com/better-auth/better-fetch/blob/main/doc/content/docs/timeout-and-retry.mdx Define a custom function to determine if a retry should occur based on the response. Allows for granular control over retry logic. ```typescript import { createFetch } from "@better-fetch/fetch"; const $fetch = createFetch({ baseURL: "http://localhost:3000", }) // ---cut--- const res = await $fetch("https://jsonplaceholder.typicode.com/todos/1", { retry: { type: "linear", attempts: 3, delay: 1000, shouldRetry: (response) => { if(response === null) return true; if(response.status === 429) return true; if(response.status !== 200) return true; return response.json().then( data => data.completed === false ).catch( err => true ) } } }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.