simpler-fetch
is a super simple to usefetch API
abstraction with ZERO dependencies (there is only optional Type level dependencies), making it super small at just 1.5kb with brotli compression!
It DOES NOT introduce any new features at all. It only simplifies the fetch API
to make it easier and more ergonomic to work with, such as by using chainable builder pattern methods to configure the fetch
options before making the fetch call, a simple way to set baseUrls, a way to delay generating headers and etc...
Since this library is just a wrapper over fetch
, it can be used in an isomorphic context as long as a spec compliant fetch
function is available in the global scope as it is not tied to any specific fetch implementation.
This library only exports a JS ES6 module, which means that it can be tree shaked when used with a bundler. However this also means that NodeJS users need to import
instead of require
, see sample project.
Note that this library does not test if fetch
is available to save that few bytes. If fetch
is not available globally, DO NOT load this library directly, load a polyfill or run a monkey patch first before loading this library.
This library is intended for any projects that want a simple to use ergonomic HTTP API client library without resorting to deal with the low level and cumbersome fetch API or use a super heavy library like axios
or superagent
.
This library is designed to make working with APIs (especially JSON APIs) extremely easy while providing first class TypeScript support to improve the development experience with strict type safety.
Migration guide for v10 to v11 major breaking change upgrade
- See full API and other technical documentations
- See CHANGELOG for specific changes across versions!
- You can find migration guides for the other major versions here
# Install from npm
npm i simpler-fetch
This library exports sf
(simpler-fetch), which lets library users use a object oriented builder pattern approach to build their API calls with chainable methods to configure API options for fetch
before every API call.
This library exports everything as named exports.
See the sample project provided for a full example on using sf
and install it to play around with it. Below are some simpler examples to get you started quickly.
// Import the library as a npm dependency
import { sf } from "simpler-fetch";
// Alternatively you can import this library directly from a CDN link
// You can use any provider, however jsDelivr is shown here as it can be used in China and it is backed by multiple CDNs
// For CDN use, PEG your code to a specific version to ensure it does not break between upgrades, e.g.
// import { sf } from "https://cdn.jsdelivr.net/npm/simpler-fetch/dist/index.js";
// Basic GET example
async function getExample() {
const [err, res] = await sf
// Make a one off API call to this URL without any base Urls
.useOnce("https://jsonplaceholder.typicode.com/todos/1")
.GET()
.runJSON();
console.log(res, err);
}
// POST request example
async function postExample() {
const [err, res] = await sf
// Make a one off API call to this URL without any base Urls
.useOnce("https://jsonplaceholder.typicode.com/posts")
.POST()
.useHeader({ someAuthenticationToken: "superSecureTokenString" })
.bodyJSON({ title: "foo", body: "bar", userId: 1 })
.runJSON();
console.log(res, err);
}
import { sf } from "simpler-fetch";
// Add a base Url and set it to be the default base Url.
sf.addBase("default", "https://deployed-api.com").setDefault("default");
// Make a POST request and use a bunch of different ways to generate header values
const [err, res] = await sf
// Use the default base Url
.useDefault()
.POST("/test")
// Can be a synchronous function that returns a header object
.useHeader(() => ({ randomHeader: "true", anotherHeader: "value" }))
// Can be an asynchronous function that returns a header Promise<object>
.useHeader(async () => ({ asyncAuthToken: await Promise.resolve("secret") }))
// Can also just directly pass in a header object. Header method can be called multiple times
.useHeader({ someAuthenticationToken: "superSecureTokenString" })
.bodyJSON({ test: "true", anotherTest: "testing" })
.runJSON();
console.log(res, err);
Once again, see the sample project provided for a full example on using the library.
This library is designed for modern browsers in mind only and does not support older browsers/node by default although you can monkey patch it to work for example by using polyfills.
- Because this library only exports a JS ES6 module, your target platform (browser/node) must support ES6 modules.
- This library relies on the modern
fetch API
, so if your platform does not have this natively, you need to monkey patch it in using apolyfill
or something likenode-fetch
.
See documentation for using this library with firebase authentication
This library supports Response validation, it supports it via user supplied validator functions instead of bringing on a validation library itself, since it is will be a huge dependency and not all users will want to use it. Not including a validation library will also mean that users have the flexibility to choose and use whatever validation library they want to use.
However, it can be troublesome for users to convert their own validation library's validators to the expected validator type of this library, therefore utility methods are exported from this library to support adapting validation libraries' validator functions to the expected validator type of this library in a type safe manner.
Here is a list of popular validation libraries that are supported with utility adapters, if your validation library is not here, you can create an issue for it and I will add a adapter if it is popular enough.
This library does not have as many advanced features as libraries like Axios
(and it will never be) but the advantage of this is that it is much simpler to learn, use and is alot smaller!
- This library is extremely simple to use compared to other libraries, with a simple and clear API built with strong types for type safety and leverages TS LSP for code completion.
- This library does exceptions handling better.
- This is subjective but take a look at it yourself.
- All the
run
methods do not throw any exceptions / let any errors bubble up to the caller, instead errors are treated as values returned together with the response if any. This means that users do not have to always write extra boilerplate code at their API call sites just to handle errors.- Read more about how this library views error handling
- This library is extremely small compared to other popular HTTP clients like
Axios
andsuperagent
, here is a comparison of the minified library after using brotli compression- 1.7kb -
simpler-fetch
- 14.3kb -
axios v1.4.0
is 9.5 times larger thansimpler-fetch
- 19.1kb -
superagent v8.0.9
is 12.7 times larger thansimpler-fetch
- 1.7kb -
- This library skips out on some more advanced features like a nice way to do automatic retries.
- However, since this library is basically a wrapper around the
fetch
API to use the Builder pattern, you have the necessary tools and escape hatches to directly configurefetch
options to implement something like that yourself.
- However, since this library is basically a wrapper around the
- This library is designed for newer platforms and doesn't support older platforms.
- Although it can work with it, as long as you downlevel the code and use a
fetch
polyfill.
- Although it can work with it, as long as you downlevel the code and use a
- This library does not support users passing in custom AbortControllers.
- The reason is because the main use case for AbortControllers are usually for setting custom timeouts and this is already supported by the
timeoutAfter
method onFetch
. - Therefore this is not supported since there are not many specific use cases for it right now.
- Might implement this in the future if there is an actual concrete use case for it.
- The reason is because the main use case for AbortControllers are usually for setting custom timeouts and this is already supported by the
- Although this library supports using the
HEAD
andOPTIONS
HTTP methods, they are not as easy to use as other common HTTP methods likeGET
andPOST
since they do not have methods named after them, e.g. there issf.useDefault().GET()
but nosf.useDefault().HEAD()
.- Since these are rather low level and extremely rarely used HTTP methods, users need to use the more cumbersome
HTTP
method onBuilder
instances like thissf.useDefault().HTTP('HEAD', '/path')
.- See the sample project for example on this.
- Since these are rather low level and extremely rarely used HTTP methods, users need to use the more cumbersome
- Yes 1.5kb is still extra overhead compared to using raw
fetch
, but if you used this library instead offetch
directly, this library will more than make up for the extra overhead with the amount of boilerplate code it removes compared to using rawfetch
many times.
- eazyfetch is the predecessor of this library that is now deprecated.
- easyfetch is the inspiration for
eazyfetch
- easyfetch is the inspiration for
- fetch-with-fire was the predecessor of the
eazyfetch
library and it was created to primarily reduce the boiler plate code needed to include auth tokens on every API call.
These are some similar projects that are all simple wrappers/abstractions on top of the fetch
API just like the old v7 of this library, but their API is more clunky (biased opinion) and more rigid. They also do not have a nice way to do error handling, where you have to deal with catching errors yourself like most other libraries.
Most of the detailed technical explanations are all written in the source code itself, either as generic comments or within JSDocs so do explore that for more details. This section just documents some details to understand why certain technical decisions were made that cannot be found in the source code.
sf
does error handling alot differently compared to other HTTP client libraries- POST, PUT and PATCH HTTP methods are all supported, see this link on the difference
- This library implements the builder pattern with 3 levels of indirection (
sf
,Builder
andFetch
classes)- Why 3? Why cant we use less classes for a smaller library?
- Yes, the library can be smaller. But with this setup, the DX is improved as it forces you to use the method chaining in a specific order / sequence that makes the more sense.
- For example
- Users can only set the JSON body after you set the base Url and path.
- Users can only set API call specific headers after you set things like HTTP methods.
- The flow of method chaining configuration
sf
class- At the root layer, you can either
- Configure the base Urls and default base Url.
- Select what base Url you would like to use.
- At the root layer, you can either
Builder
class- At the second layer, you can either
- Select a HTTP method and Url path to use for the API call.
- Configure default
RequestInit
options or Header values for all future API calls on the same base Url.
- Selecting the HTTP methods involve using instance methods like
GET
orPOST
with an optional path
- At the second layer, you can either
Fetch
class- At the last layer, you get to configure options for the specific API call before actually making the API call.
- Some of the things you can configure are
- The specific headers needed
- Request body
- Custom
RequestInit
options - Custom timeout value
- After configuration, you can make the API call using the
run
methods such asrun
to get the raw Response object back fromwindow.fetch
runJSON
to get response back as a JSON valuerunText
to get response back as a StringrunBlob
to get response back as a BlobrunFormData
to get response back as Form DatarunArrayBuffer
to get response back as an ArrayBuffer
- All the run methods also support passing in an optional validator to do Response Validation.
- See above section on Response Validation.
- Why 3? Why cant we use less classes for a smaller library?
Archived version v8 of this library. You can find its source code and documentation here
In older versions of this library, there was another abstraction on top of the fetch
API to simplify the API and do body stringification if needed. But because it was not very practical and generally not really used, it has been removed/abandoned now. You can find its source code and documentation here
In older versions of this library, there was another abstraction on top of _fetch
built for functional programming. But because it was not very practical and generally not really used, it has been removed/abandoned now. You can find its source code and documentation here
This project is developed by JJ and made available under the MIT License. Feel free to use it however you like and open a github issue if you have any questions or problems!