This package has been deprecated

Author message:

Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

@better-tools/fetch
TypeScript icon, indicating that this package has built-in type declarations

1.3.3 • Public • Published

Better Fetch

A fetch wrapper for typescript that returns data and error object, supports defined route schemas, plugins and more. Works on the browser, node (version 18+), workers, deno and bun.

Installation

pnpm install @better-tools/fetch

Basic Usage

import betterFetch from "@better-tools/fetch"

const { data, error } = await betterFetch<{
  userId: number;
  id: number;
  title: string;
  completed;
}>("https://jsonplaceholder.typicode.com/todos/1");
if (error) {
  // handle the error
}
if (data) {
  // handle the data
}

♯ Create a custom fetch

You can create a custom fetch with default options.

import { createFetch } from "@better-tools/fetch";

const $fetch = createFetch({
  baseUrl: "https://jsonplaceholder.typicode.com",
  retry: 2,
});

const { data, error } = await $fetch<{
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}>("/todos/1");

♯ Typed Fetch

Better fetch allows you to define zod schema that will be used to infer request body, query parameters, response data and error types.

  pnpm install zod
import { createFetch } from "@better-tools/fetch";
import { FetchSchema } from "@better-tools/fetch/typed";
import { z } from "zod";
const routes = {
	"/": {
		output: z.object({
			message: z.string(),
		}),
	},
	"/signin": {
		input: z.object({
			username: z.string(),
			password: z.string(),
		}),
		output: z.object({
			token: z.string(),
		}),
	},
	"/signup": {
		input: z.object({
			username: z.string(),
			password: z.string(),
			optional: z.optional(z.string()),
		}),
		output: z.object({
			message: z.string(),
		}),
	},
	"/query": {
		query: z.object({
			term: z.string(),
		}),
	},
} satisfies FetchSchema;

const $fetch = createFetch<typeof routes>()

You can also pass default response and error types. Which will be used if you don't pass the types in the fetch call.

import { createFetch } from "@better-tools/fetch";
import { DefaultSchema } from "@better-tools/fetch/typed";

const $fetch = createFetch<DefaultSchema,{
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}, {
  message: string;
}>({
  baseUrl: "https://jsonplaceholder.typicode.com",
  retry: 2,
});

const { data, error } = await $fetch("/todos/1");
//data and error types are inferred from the default types

const { data, error } = await $fetch<{
  some: string;
}, {
  fields: string[]
}>("/todos/1");
//data and error types are inferred from fetch call

♯ Using with React

To use better fetch with React hooks, you have the option to import createReactFetch. This allows you to create hooks with custom defaults. Alternatively, you can directly import each individual hook.

With createReactFetch, you can create hooks with custom defaults.

import {  createReactFetch  } from "@better-tools/fetch/react";

//create hooks with custom defaults
const { useFetch, useMutate } = createReactFetch({
  baseUrl: "https://jsonplaceholder.typicode.com",
  retry: 2,
});

function App() {
  type Todo = {
    userId: number;
    id: number;
    title: string;
    completed: boolean;
  };
  const { data, error, isPending } = useFetch<Todo>("/todos/1");
  if (error) {
    // handle the error
  }
  if (data) {
    // handle the data
  }
  const { mutate, isPending } = useMutate<Todo>("/todos")
  await mutate({
    userId: 1,
    id: 1,
    title: "delectus aut autem",
    completed: false 
  })
}

Alternatively, you can directly import each individual hook.

import { useFetch, useMutate } from "@better-tools/fetch/react";

function App() {
  const { data, error } = useFetch<{
    userId: number;
    id: number;
    title: string;
    completed: boolean;
  }>("https://jsonplaceholder.typicode.com/todos/1");
  if (error) {
    // handle the error
  }
  if (data) {
    // handle the data
  }
}

♯ Plugins

Plugins are functions that can be used to modify the request, response, error and other parts of the request lifecycle.

Example:

import { createFetch } from "@better-tools/fetch";
import { csrfProtection } from "./plugins/csrfProtection"

const $fetch = createFetch({
  baseUrl: "https://jsonplaceholder.typicode.com",
  retry: 2,
  plugins: [csrfProtection()]
});

♯ Parsing the response

Better fetch will smartly parse JSON using JSON.parse and if it fails it will return the response as text.

For binary content types, better fetch will instead return a Blob object.

You can also pass custom parser.

//parsed as JSON
const { data, error } = await fetch("/todos/1");
// Get the blob version of the response
const { data, error } = await fetch("/api/image.png");
// Return text as is
await ofetch("/ok");
//custom parser
const { data, error } = await fetch("/todos/1", {
  parser: (text) => {
    return JSON.parse(text);
  },
});

♯ Handling Errors

By default better fetch will return the error object if the request fails. You can also pass the throw option to throw if the request fails.

const { data, error } = await fetch<
  {
    userId: number;
    id: number;
    title: string;
    completed;
  },
  {
    message: string;
  }
>("https://jsonplaceholder.typicode.com/todos/1");
if (error) {
  // handle the error
}

throws if the request fails

const { data, error } = await fetch<{
  userId: number;
  id: number;
  title: string;
  completed;
}>("https://jsonplaceholder.typicode.com/todos/1", {
  throw: true,
});

♯ Auto Retry

You can set the number of retries.

const { data, error } = await fetch<{
  userId: number;
  id: number;
  title: string;
  completed;
}>("https://jsonplaceholder.typicode.com/todos/1", {
  retry: 2,
});

♯ Timeout

You can set the timeout in milliseconds.

const { data, error } = await fetch<{
  userId: number;
  id: number;
  title: string;
  completed;
}>("https://jsonplaceholder.typicode.com/todos/1", {
  timeout: 5000,
});

♯ Query Parameters

You can pass the query parameters as an object.

const { data, error } = await fetch<{
  userId: number;
  id: number;
  title: string;
  completed;
}>("https://jsonplaceholder.typicode.com/todos/1", {
  query: {
    userId: 1,
  },
});

♯ Callbacks

You can pass callbacks for different events on the request lifecycle.

const { data, error } = await fetch<{
  userId: number;
  id: number;
  title: string;
  completed;
}>("https://jsonplaceholder.typicode.com/todos/1", {
  onRequest: (request) => {
    console.log("Requesting", request);
  },
  onResponse: (response) => {
    console.log("Response", response);
  },
  onError: (error) => {
    console.log("Error", error);
  },
  onSuccess: (data) => {
    console.log("Success", data);
  },
  onRetry: (retry) => {
    console.log("Retrying", retry);
  },
});

♯ Native Fetch

You can use the native fetch by calling the native method.

import betterFetch from "better-fetch";
const res = await betterFetch.native(
  "https://jsonplaceholder.typicode.com/todos/1"
);

License

MIT

Readme

Keywords

none

Package Sidebar

Install

npm i @better-tools/fetch

Weekly Downloads

6

Version

1.3.3

License

none

Unpacked Size

155 kB

Total Files

21

Last publish

Collaborators

  • bekacru