SkillAgentSearch skills...

Wretch

A tiny wrapper built around fetch with an intuitive syntax. :candy:

Install / Use

/learn @elbywan/Wretch

README

<h1 align="center"> <a href="https://elbywan.github.io/wretch"><img src="assets/wretch.svg" alt="wretch-logo" width="220px"></a><br> <br> <a href="https://elbywan.github.io/wretch">Wretch</a><br> <br> <a href="https://github.com/elbywan/wretch/actions/workflows/node.yml"><img alt="github-badge" src="https://github.com/elbywan/wretch/actions/workflows/node.yml/badge.svg"></a> <a href="https://www.npmjs.com/package/wretch"><img alt="npm-badge" src="https://img.shields.io/npm/v/wretch.svg?colorB=ff733e" height="20"></a> <a href="https://www.npmjs.com/package/wretch"><img alt="npm-downloads-badge" src="https://img.shields.io/npm/dm/wretch.svg?colorB=53aabb" height="20"></a> <a href="https://coveralls.io/github/elbywan/wretch?branch=master"><img src="https://coveralls.io/repos/github/elbywan/wretch/badge.svg?branch=master" alt="Coverage Status"></a> <a href="https://bundlejs.com/?q=wretch#sharing"><img src='https://deno.bundlejs.com/badge?q=wretch'/></a> <a href="https://github.com/elbywan/wretch/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license-badge" height="20"></a> </h1> <h4 align="center"> A tiny (~1.8KB g-zipped) wrapper built around <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">fetch</a> with an intuitive syntax. </h4> <h5 align="center"> <i>f[ETCH] [WR]apper</i> </h6> <br>
Wretch 3.0 is now live 🎉 ! Check out the Migration Guide for upgrading from v2, and please have a look at the releases and the changelog after each update for new features and breaking changes.
And if you like the library please consider becoming a sponsor ❤️.

Features

wretch is a small wrapper around fetch designed to simplify the way to perform network requests and handle responses.

  • 🪶 Small - core is less than 1.8KB g-zipped
  • 💡 Intuitive - lean API, handles errors, headers and (de)serialization
  • 🧊 Immutable - every call creates a cloned instance that can then be reused safely
  • 🔌 Modular - plug addons to add new features, and middlewares to intercept requests
  • 🧩 Isomorphic - compatible with modern browsers, Node.js 22+, Deno and Bun
  • 🦺 Type safe - strongly typed, written in TypeScript
  • Proven - fully covered by unit tests and widely used
  • 💓 Maintained - alive and well for many years

Table of Contents

Quick Start

# 1️⃣ Install
npm i wretch
<!-- snippet: Quick start example snippet:description Quick start example showing basic wretch usage -->
// 2️⃣ Import and create a reusable API client
import wretch from "wretch"

const api = wretch("https://jsonplaceholder.typicode.com")
  .options({ mode: "cors" })

// 3️⃣ Make requests with automatic JSON handling
const post = await api.get("/posts/1").json()
console.log(post.title)

// 4️⃣ POST with automatic serialization
const created = await api
  .post({ title: "New Post", body: "Content", userId: 1 }, "/posts")
  .json()

// 5️⃣ Handle errors elegantly
await api
  .get("/posts/999")
  .notFound(() => console.log("Post not found!"))
  .json()

// 6️⃣ Different response types
const text = await api.get("/posts/1").text()      // Raw text
const response = await api.get("/posts/1").res()   // Raw Response object
const blob = await api.get("/photos/1").blob()     // Binary data

Motivation

Because having to write a second callback to process a response body feels awkward.

Fetch needs a second callback to process the response body.

<!-- snippet:description Fetch requires two callbacks for JSON parsing -->
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then(response => response.json())
  .then(json => {
    //Do stuff with the parsed json
  });

Wretch does it for you.

<!-- snippet:description Fetch with two callbacks for JSON parsing snippet:expect-return "userId" -->
// Use .res for the raw response, .text for raw text, .json for json, .blob for a blob …
wretch("https://jsonplaceholder.typicode.com/posts/1")
  .get()
  .json(json => {
    // Do stuff with the parsed json
    return json
  });

Because manually checking and throwing every request error code is tedious.

Fetch won't reject on HTTP error status.

<!-- snippet:description Fetch requires manual error code checking -->
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then(response => {
    if(!response.ok) {
      if(response.status === 404) throw new Error("Not found")
      else if(response.status === 401) throw new Error("Unauthorized")
      else if(response.status === 418) throw new Error("I'm a teapot !")
      else throw new Error("Other error")
    }
    else {/* … */}
  })
  .then(data => {/* … */})
  .catch(error => { /* … */ })

Wretch throws when the response is not successful and contains helper methods to handle common codes.

<!-- snippet:description Shows error handling with wretch catchers -->
wretch("https://jsonplaceholder.typicode.com/posts/1")
  .get()
  .notFound(error => { /* … */ })
  .unauthorized(error => { /* … */ })
  .error(418, error => { /* … */ })
  .res(response => {/* … */ })
  .catch(error => { /* uncaught errors */ })

Because sending a json object should be easy.

With fetch you have to set the header, the method and the body manually.

<!-- snippet:description Manual JSON request setup with fetch -->
fetch("https://jsonplaceholder.typicode.com/posts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ "hello": "world" })
}).then(response => {/* … */})
// Omitting the data retrieval and error management parts…

With wretch, you have shorthands at your disposal.

<!-- snippet:description Posting JSON data with automatic serialization -->
wretch("https://jsonplaceholder.typicode.com/posts")
  .post({ "hello": "world" })
  .res(response => { /* … */ })

Because configuration should not rhyme with repetition.

A Wretch object is immutable which means that you can reuse previous instances safely.

<!-- snippet:description Reusable wretch instances with base configuration -->
const token = "MY_SECRET_TOKEN"

// Cross origin authenticated requests on an external API
const externalApi = wretch("https://jsonplaceholder.typicode.com") // Base url
  // Authorization header
  .auth(`Bearer ${token}`)
  // Cors fetch options
  .options({ credentials: "include", mode: "cors" })
  // Handle 403 errors
  .resolve((w) => w.forbidden(error => { /* Handle all 403 errors */ }));

// Fetch a resource
const resource = await externalApi
  // Add a custom header for this request
  .headers({ "If-Unmodified-Since": "Wed, 21 Oct 2015 07:28:00 GMT" })
  .get("/posts/1")
  .json(() => {/* do something with the resource */});

// Post a resource
externalApi
  .url("/posts")
  .post({ "Shiny new": "resource object" })
  .json(() => {/* do something with the created resource */});

Installation

Package Manager

npm i wretch # or yarn/pnpm add wretch

<script> tag

The package contains multiple bundles depending on the format and feature set located under the /dist/bundle folder.

<details> <summary>Bundle variants</summary> <br>

💡 If you pick the core bundle, then to plug addons you must import them separately from /dist/bundle/addons/[addonName].min.js

| Feature set | File Name | | ------------------ | ------------------- | | Core features only | wretch.min.js | | Core + all addons | wretch.all.min.js |

| Format | Extension | | -------- | ---------- | | ESM | .min.mjs | | CommonJS | .min.cjs | | UMD | .min.js |

</details>
<!--
  Pick your favourite CDN:
    - https://unpkg.com/wretch
    - https://cdn.jsdelivr.net/npm/wretch/
    - https://www.skypack.dev/view/wretch
    - https://cdnjs.com/libraries/wretch
    - …
-->

<!-- UMD import as window.wretch -->
<script src="https://unpkg.com/wretch"></script>

<!-- Modern import -->
<script type="module">
  import wretch from 'https://cdn.skypack.dev/wretch/dist/bundle/wretch.all.min.mjs'

  // … //
</script>

Compatibility

Browsers

wretch@^3 is compatible with modern browsers only. For older browsers please use wretch@^1.

Node.js

Wretch is compatible with and tested in Node.js >= 22.

For older Node.js versions, please use wretch@^2.

Node.js 22+ includes native fetch support and all required Web APIs (FormData, URLSearchParams, AbortController, etc.) out of the box, so no polyfills are needed.

Deno

Works with Deno out of the box.

deno add npm:wretch
<!-- snippet:description Basic Deno usage example -->
import wretch from "wretch";

const text = await wretch("https://httpbingo.org").get("/status/200").text();
console.log(text); // -> { "code": 200, "description": "OK" }

Bun

Works with Bun out of the box.

bun add wretch
<!-- snippet:description Basic Bun usage example -->
import wretch from "wretch";

const text = await wretch("https://httpbingo.org").get("/status/200").text();
console.log(text); // -> { "code": 200, "description": "OK" }

Usage

Import

<!-- snippet:description Browser module import examples snippet:skip Browser specific code -->
View on GitHub
GitHub Stars5.2k
CategoryDevelopment
Updated4d ago
Forks107

Languages

TypeScript

Security Score

100/100

Audited on Mar 20, 2026

No findings