soFetch.

A concise HTTP client
optimised for JSON apis

A POST request using fetch:

const newUser = {
    name:"Regina George", 
    email:"regina@massive-deal.com"
}

const response = await fetch("/api/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(newUser)
})

const success = await response.json() as Success

The same POST request in soFetch:

const newUser = {
    name:"Regina George", 
    email:"regina@massive-deal.com"
}

const success = await soFetch<Success>("/api/users", newUser)

Less Code.
More Fetch.

soFetch is a lightweight wrapper around the FetchAPI that reduces boilerplate, handles errors fluently and simplifies authentication.

Built for JSON

Defaults to JSON for both the request and the response

Fluent Error Handling

Makes it easy to handle multiple error codes, for a single request or globally

Easy Authentication

Includes helpers for most modern authentication methods

Build Multiple Clients

Configure several instances simultaneously to connect with multiple services

Handle Timeouts

Configurable timeouts with sensible defaults out of the box


🌱Install.

NPM:
npm i @antoinette-agency/sofetch
PNPM:
pnpm add @antoinette-agency/sofetch
Yarn:
yarn add @antoinette-agency/sofetch
Bun:
bun install @antoinette-agency/sofetch

⏩Quickstart.

A GET request looks like:

const products = await soFetch<Product[]>("/api/products")

A POST request is just:

const newUser = {
    name:"Regina George", 
    email:"regina@massive-deal.com"
}
const newUserResponse = await soFetch<NewUserResponse>("/api/users", newUser)

What about PUT, PATCH and DELETE?

//A PUT request:
const upsertUser = {
    name:"Regina George",
    email:"regina@massive-deal.com"
}
const successResponse = await soFetch.put<Success>("/api/users/1234", upsertUser)
//A PATCH request:
const updateUserEmail = {
    email:"regina@massive-deal.com"
}
const successResponse = await soFetch.patch<Success>("/api/users/1234", updateUserEmail)
//A DELETE request:
await soFetch.delete("/api/users/1234")

⚠️Handling Errors.

SoFetch has lots of options to help you handle errors flexibly. A soFetch request returns an await-able promise, so if you want to handle any kind of error it's just:

const result = await soFetch("/api/unicorns/1234").catch((e:any) => {
    console.error(e)
    alert("An unexpected error occurred")
})

But what if you wanted to handle a specific error like a 404 - Not Found? In that case you can use .catchHttp() like this:

const result = await soFetch("/api/unicorns/1234").catchHttp(404, (r:Response) => {
    alert("This unicorn could not be found.")
})

You can even chain .catchHttp() statements together:

const result = await soFetch("/api/unicorns/1234")
.catchHttp(404, (r:Response) => {
    alert("This unicorn could not be found.")
})
.catchHttp(419, (r:Response) => {
    alert("This unicorn has expired.")
})
.catch((e:any) => {
    //This code will execute if the HTTP response code is not 404 or 419:
    alert("An unexpected error occurred")
})

Global Error Handlers.

You might find that you want to use the same error handler for all statuses of a certain type. For example, you might want all 401 - Unauthorized responses to redirect the user to a login page. To do that you can add an error handler to thesoFetch.config like this:

soFetch.config.catchHttp(401, (res:Response) => {
    window.location.href = "/login";
})
© 2025 AntoinettePrivacy