Why "KY" is Like fetch(), But Better (and When to Consider It)
In the world of JavaScript, the landscape of making HTTP requests has evolved significantly. Not long ago, axios was the go-to library for handling server communication, providing a reliable and consistent way to fetch data on the client. However, with the advent of fetch, which has become the standard for modern web development, many developers have shifted to using it as their primary tool. While fetch is undoubtedly a powerful and flexible tool, it isn't without its quirks and limitations.
This brings us to "KY," a small and elegant HTTP client that offers a more convenient API for making HTTP requests. In this blog post, we'll explore why KY might be a better alternative to fetch() for certain use cases, and when it makes sense to adopt it in your project.
A Brief History of HTTP Requests in JavaScript
Before fetch became widely available, developers relied heavily on axios for making HTTP requests. Axios was popular because it handled many common tasks, like setting default headers or dealing with JSON responses, in a way that was more straightforward than the older XMLHttpRequest. However, once fetch was introduced, it quickly became the standard due to its simplicity and the fact that it was built into the browser.
That said, while fetch is great, it's not perfect. For instance:
- It doesn't treat non-200 status codes as errors by default.
- It lacks built-in timeout support.
- Retrying failed requests is something you have to implement yourself.
- Working with JSON in fetch can be tricky and often leads to mistakes, especially for those new to the API.
These shortcomings create an opportunity for a library like KY to come in and smooth out some of these rough edges.
What is KY?
KY is a small HTTP client built on top of the fetch API. It offers a simplified API that addresses many of the pain points associated with fetch, including:
- Error Handling: Non-200 responses are treated as errors, so you can use try/catch blocks more effectively.
- Timeout Support: KY includes built-in support for request timeouts.
- Retry Mechanism: KY can automatically retry failed requests, with a default of two retries.
- Improved TypeScript Support: When working with JSON, KY’s TypeScript support ensures that you get better type safety.
Here’s a quick comparison:
With fetch:
async function getTodos() {
const response = await fetch('/todos');
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
}
async function addTodo(todo) {
const response = await fetch('/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(todo)
});
if (!response.ok) throw new Error('Failed to add todo');
return response.json();
}
With KY:
import ky from 'ky';
async function getTodos() {
return await ky.get('/todos').json();
}
async function addTodo(todo) {
return await ky.post('/todos', { json: todo }).json();
}
领英推荐
Customizing request
To add the access token for each request, you can use the following code with ky:
const api = ky.create({
prefixUrl: "https://example.com/api",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
// use a hook to add the authorization header before each request
hooks: {
beforeRequest: [
(request) => {
request.headers.set("Authorization", "Bearer token")
},
],
},
})
const response = await api.get("users")
const data = await response.json()
console.log(data)
Notice that:
The Trade-Offs
While KY offers some clear benefits, it’s important to weigh the trade-offs before deciding to include it in your project. The primary advantage of fetch is its ubiquity; every web developer is familiar with it, and it's a part of the standard API, meaning there's zero cognitive overhead when a new developer joins your team.
KY, while small (just 3.3 KB minified and Gzipped), introduces an additional dependency. In a large project with many developers, even small dependencies can add up in terms of maintenance and cognitive load.
Moreover, KY's improvements over fetch might not be significant enough to justify its inclusion in every project. For example, if you're already using a library like React Query, which abstracts away a lot of the boilerplate associated with fetch, the benefits of KY might be negligible.
KY vs. React Query
It’s worth noting that KY is not a replacement for something like React Query. React Query simplifies data fetching in React by handling caching, synchronization, and more. The difference between vanilla React with fetch and using React Query is massive, making React Query almost indispensable for React developers dealing with asynchronous data.
On the other hand, the difference between fetch and KY is more subtle. It might save you a few lines of code and make certain things a bit easier, but it's not going to revolutionize the way you write your data-fetching logic.
When Should You Use KY?
Consider using KY if:
- You frequently find yourself writing repetitive boilerplate code with fetch.
- You need features like automatic retries or better error handling but don't want to implement them from scratch.
- You're working on a smaller project where introducing a new dependency isn't a big concern.
- You want slightly better ergonomics when working with JSON and TypeScript.
However, if you're already using a more comprehensive solution like React Query or if you're working in a large team where consistency is key, sticking with fetch might be the better choice.
KY is a neat little tool that smooths over some of the rough edges of fetch. While it won't completely replace fetch in every project, it offers enough convenience to be worth considering, especially in smaller projects or for developers who want to avoid some of the common pitfalls associated with fetch. Just remember, every abstraction comes with its trade-offs, and it’s essential to weigh the benefits against the potential downsides before making a decision.
Until next time, fetch wisely!