Skip to main content

Command Palette

Search for a command to run...

wretch Tiny Wrapper: Tiny fetch Wrapper

Updated
6 min read
T

Welcome to TopperBlog! 👋

I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.

🎯 What I Write About: • AI/ML Engineering & LLMs • Web3 & Blockchain Development
• System Design & Architecture • Interview Preparation (FAANG) • Freelancing & Remote Work • Modern Tech Stacks (Next.js, React, Rust, TypeScript) • Performance Optimization & Best Practices

💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.

📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.

🌐 Let's connect and grow together in this amazing tech journey!

#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering

Wretch: The Tiny Fetch Wrapper That Changed How I Handle HTTP Requests

Table of Contents

  1. The Hook: My API Nightmare
  2. What is Wretch?
  3. Setup and Installation
  4. 5 Essential Patterns
  5. Comparison Table
  6. 3 Common Mistakes
  7. FAQ
  8. Conclusion

The Hook: My API Nightmare

I still remember that Tuesday afternoon when everything fell apart. My production app was throwing cryptic errors, users were complaining, and I was drowning in a sea of .then() chains and error handling logic that looked like spaghetti code had a baby with a nightmare.

The culprit? My fetch implementation. I'd been using vanilla fetch() for months, thinking I was being a "purist" developer. But the reality was brutal: every API call required 20+ lines of boilerplate, error handling was inconsistent, and I was basically copy-pasting the same code everywhere.

That's when I discovered wretch. This tiny 3KB library transformed my HTTP requests from chaotic messes into elegant, chainable one-liners. I'm not exaggerating when I say it saved my sanity.

What is Wretch Tiny Wrapper?

Wretch is a minimalist wrapper around the Fetch API that makes HTTP requests actually enjoyable to write. Think of it as fetch's cooler, more organized sibling who actually has their life together.

Why wretch exists:

  • Vanilla fetch is verbose and repetitive
  • Error handling requires manual checking of response.ok
  • No built-in retry logic or middleware support
  • JSON parsing needs extra steps every single time

What makes wretch special:

  • Tiny footprint: Only 3KB gzipped
  • Chainable API: Fluent, readable syntax
  • Smart defaults: Automatic JSON parsing and error handling
  • Middleware support: Intercept and modify requests/responses
  • TypeScript-first: Excellent type definitions out of the box

I've used Axios, got-fetch, and a dozen other libraries. Wretch hits the sweet spot between power and simplicity.

Setup and Installation

Getting started is ridiculously simple. Here's how I set it up in every project:

// Install via npm
npm install wretch

// Or with yarn
yarn add wretch

// Basic import
import wretch from 'wretch';

// Create a base instance with common config
const api = wretch('https://api.example.com')
  .headers({
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  })
  .options({ credentials: 'include' });

// Now you're ready to make requests!

Pro tip: I always create a dedicated api.js file where I configure my base wretch instance. This keeps all my API configuration in one place:

// api.js
import wretch from 'wretch';
import QueryStringAddon from 'wretch/addons/queryString';

const api = wretch('https://api.myapp.com/v1')
  .addon(QueryStringAddon)
  .auth(`Bearer ${getToken()}`)
  .errorType('json')
  .resolve(r => r.json());

export default api;

5 Essential Patterns You'll Use Every Day

Pattern 1: Simple GET Requests with Error Handling

This is where wretch shines. Compare vanilla fetch to wretch:

// The old way (vanilla fetch) - yuck
fetch('https://api.example.com/users/123')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

// The wretch way - beautiful
wretch('https://api.example.com/users/123')
  .get()
  .json(data => console.log(data))
  .catch(error => console.error('Error:', error));

I use this pattern constantly. It's clean, readable, and handles errors automatically.

Pattern 2: POST Requests with Automatic JSON Serialization

// Creating a new user
const newUser = {
  name: 'Jane Doe',
  email: 'jane@example.com',
  role: 'admin'
};

wretch('https://api.example.com/users')
  .post(newUser)
  .json(user => {
    console.log('User created:', user);
    // Automatically parsed JSON response
  })
  .catch(error => {
    // Handles 400, 500 errors automatically
    console.error('Failed to create user:', error);
  });

No more JSON.stringify() everywhere. Wretch handles it automatically.

Pattern 3: Middleware for Authentication

This pattern changed my life. I used to manually add auth headers to every request:

// Create an auth middleware
const authMiddleware = next => (url, opts) => {
  const token = localStorage.getItem('authToken');
  return next(url, {
    ...opts,
    headers: {
      ...opts.headers,
      'Authorization': `Bearer ${token}`
    }
  });
};

// Apply it globally
const authenticatedApi = wretch()
  .middlewares([authMiddleware])
  .url('https://api.example.com');

// Now all requests are authenticated
authenticatedApi.url('/protected-resource')
  .get()
  .json(data => console.log(data));

Pattern 4: Retry Logic for Flaky APIs

We've all dealt with unreliable third-party APIs. Here's how I handle retries:

import wretch from 'wretch';
import { retry } from 'wretch/middlewares';

const resilientApi = wretch('https://flaky-api.com')
  .middlewares([
    retry({
      delayTimer: 1000,
      delayRamp: (delay, nbOfAttempts) => delay * nbOfAttempts,
      maxAttempts: 3,
      until: (response, error) => {
        return response && response.ok;
      }
    })
  ]);

// This will retry up to 3 times with exponential backoff
resilientApi.url('/sometimes-fails')
  .get()
  .json(data => console.log('Finally got it:', data));

Pattern 5: Query Parameters Made Easy

import QueryStringAddon from 'wretch/addons/queryString';

const api = wretch('https://api.example.com')
  .addon(QueryStringAddon);

// Clean query parameter handling
api.url('/users')
  .query({
    page: 2,
    limit: 20,
    sort: 'created_at',
    filter: 'active'
  })
  .get()
  .json(users => console.log(users));

// Generates: /users?page=2&limit=20&sort=created_at&filter=active

Wretch vs. The Competition

FeatureWretchAxiosVanilla Fetch
Bundle Size3KB13KB0KB (native)
Chainable API
Auto JSON Parse
Middleware Support
TypeScript Support
Learning CurveLowMediumLow
Error HandlingAutomaticAutomaticManual
Browser SupportModernAllModern

3 Common Mistakes (That I Made So You Don't Have To)

Mistake 1: Forgetting to Call the HTTP Method

// WRONG - This doesn't actually make a request
wretch('https://api.example.com/users')
  .json(data => console.log(data));

// RIGHT - Always call .get(), .post(), etc.
wretch('https://api.example.com/users')
  .get()
  .json(data => console.log(data));

I spent 30 minutes debugging this once. Don't be like me.

Mistake 2: Not Handling Errors Properly

// WRONG - Unhandled promise rejection
wretch('https://api.example.com/users')
  .get()
  .json(data => console.log(data));

// RIGHT - Always add error handling
wretch('https://api.example.com/users')
  .get()
  .json(data => console.log(data))
  .catch(error => {
    console.error('API Error:', error.status, error.message);
  });

Mistake 3: Creating New Instances Instead of Reusing

// WRONG - Inefficient, repeats configuration
wretch('https://api.example.com')
  .headers({ 'Authorization': 'Bearer token' })
  .get('/users');

wretch('https://api.example.com')
  .headers({ 'Authorization': 'Bearer token' })
  .get('/posts');

// RIGHT - Create a base instance
const api = wretch('https://api.example.com')
  .headers({ 'Authorization': 'Bearer token' });

api.get('/users');
api.get('/posts');

Frequently Asked Questions

Q: Should I use wretch instead of Axios?

A: If you're building a modern app and care about bundle size, absolutely. Wretch is 4x smaller and has a more intuitive API. I switched all my projects from Axios to wretch and never looked back.

Q: Does wretch work with React/Vue/Angular?

A: Yes! Wretch is framework-agnostic. I use it with React hooks, Vue composables, and plain JavaScript. It works everywhere fetch works.

Q: Can I use wretch for file uploads?

A: Definitely. Use .formData() for multipart uploads:

const formData = new FormData();
formData.append('file', fileInput.files[0]);

wretch('/upload')
  .formData(formData)
  .post()
  .json(response => console.log(response));

Q: Is wretch production-ready?

A: Absolutely. I've used it in production apps serving millions of requests. It's stable, well-maintained, and has excellent TypeScript support.

Q: What about Internet Explorer support?

A: Wretch requires fetch API support. For older browsers, include a fetch polyfill. But honestly, if you're still supporting IE in 2024, we need to have a different conversation.

Conclusion

Wretch transformed how I write HTTP requests. It's not just about saving lines of code—though it does that brilliantly. It's about writing code that's actually pleasant to read and maintain.

The tiny 3KB footprint means I'm not bloating my bundle. The chainable API means my code reads like English. The automatic error handling means I sleep better at night knowing my apps won't crash from unhandled promise rejections.

If you're still using vanilla fetch with 20 lines of boilerplate per request, or if you're dragging around Axios's 13KB just to make HTTP calls, give wretch a try. Start with one API call. Refactor one function. I promise you'll be hooked.

That Tuesday afternoon when everything broke? It taught me that the right tools matter. Wretch is the right tool for HTTP requests. Simple as that.