You Don't Need Axios
Tags: webdev, javascript, programming, node
Published: 2023-10-24 01:38:15

You don't need Axios, well, for most use cases. The web is maturing, and the days of Axios are ending.

## Why we needed Axios

For newcomers, not long ago, we needed to use `XMLHttpRequest` to fetch data from servers. To fetch data from https://jsonplaceholder.typicode.com/todos/, we would have needed the following lines of code at the very minimum.

```ts
const req = new XMLHttpRequest();
req.addEventListener("load", function() {
  console.log(JSON.parse(this.responseText))
})

req.open('GET', 'https://jsonplaceholder.typicode.com/todos/')
req.send()
```

We needed an elegant abstraction over XMLHttpRequest, and `axios` filled that space perfectly, especially with the introduction of Promise in ES6.

With `axios`, we can achieve the same thing with just one line of code

``` ts
	const data = (await axios.get('https://jsonplaceholder.typicode.com/todos/')).data
```
But time has passed, the web has matured, and now, we have `fetch()`

## Use fetch() Instead

With fetch, you get most of the benefits of Axios with zero external dependencies in your application. I am a proponent of minimal dependencies. If the platform I'm on provides a functionality, and it's relatively easy to implement, I'll explore it first. This is even more important with JavaScript runtimes, as every abstraction comes at a cost.


### GET Request Using Fetch


```ts
	const data = await fetch('https://jsonplaceholder.typicode.com/todos/')).then(res => res.json())
```

### POST Request Using Fetch

The fetch API takes in a second parameter, which allows you to specify other options, including your HTTP method, headers, and body. The example below shows how to make a post request using fetch API. This example also applies to other HTTP methods that mutate the server; 
 
```ts
	const data = await 	fetch('https://jsonplaceholder.typicode.com/todos/', { 
  method: 'POST', 
  body: JSON.stringify({title: 'buy milk'})
}).then(res => res.json())
```

### Uploading Files

Assuming you have the following HTML file

```html
<!Docktype html>
<html lang=en>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width initial-scale=1.0">
		<meta http-eqiv="X-UA-Compatibly" content="ie=edge">
		<title>File Upload</title>
	</head>
	<body>
		<form id="fileform" enctype="multipart/form-data">
			<input name="upload"  type="file" placeholder="upload file" />
			<button type="submit">submit</button>
		</form>
		<script src="./index.js"></script>
	</body>
</html>
```
then your fetch call would look like this:

```js
const form = document.getElementById("fileform")

form.addEventListener("submit", (event) => {
	event.preventDefault();
	const fileInput = document.getElementsByName('upload')[0]
	
	const fd = new FormData()
	fd.append('upload', fileInput.files[0]);

	fetch('http://localhost:5001/upload', { method: 'POST', body: fd}).then(res => res.json().then(body => console.log('result', body)))
})
```

### Pro Tip

Always wrap your fetch function in with another function; This gives you leeway for abstracting HTTP call patterns emerging as your application grows. See the code snippet below.

```ts
 const originalFetch = window.fetch
window.fetch = async (...args) => {
	// intercept request
	const res = originalFetch(...args)
	// intercept response e.g
	if(res.ok) {
		return res.json()
	} else
		//Do whatever you want to handle the error
	}
}
```

## The Whataboutisms

### What about Request and Response Interceptors

We've talked about that briefly in the previous subheading



``` ts
	const interceptRequest = (...args) => {
		// perform some magic
		return args
	}
        
	const interceptResponse = (res) => {
		// perform some magic
		return res;
	}

 const originalFetch = window.fetch
window.fetch = async (...args) => {
	const modifiedArgs = interceptRequest(...args)
	const res = await orginalFetch(modifiedArgs)
	return interceptResponse(res)
}
```

#### Edit 24 Oct 2023 More On Intercepting Requests
Due to questions from colleagues, I realized I needed to address this a little more. 

To intercept means to stop something from proceeding. Interceptors in HTTP libraries(you could call them middleware), stop requests and modify the request configuration using your provided function. For response, interceptors take raw server responses and modify them based on your logic before returning them to the library consumers.

These can be implemented as simple functions that get called before and after your call to `fetch`

Axios and other JS libraries don't do magic with your interceptors. They only call the functions you give to them and call them for you

### What About Timeouts

Timeouts should primarily be the business of your backend. It would help if you also had a backend that integrates the third-party platforms, but should you choose to incorporate an unreliable backend with your frontend, you can still implement timeouts with fetch API so

```ts
// timeout request after 5 seconds
const res = await fetch('https://jsonplaceholder.typicode.com/todos/', { abort: AbortSignal.timeout(5000) })
```

###  What About Javascript In The Backend, Aka Nodejs/Deno/Bun

The three significant runtimes now implement fetch, and if you must install any HTTP client for your javascript backend, install `undici.` Undici is an HTTP client built from the ground for nodejs, and the nodejs organization maintains it. Undici also implements fetch API

### What about a progress update for large file uploads

Use XMLHttpRequest ;). Unfortunately, fetch() has yet to include this feature.

## Conclusion

Regarding dependencies, I follow the [YAGNI principle in extreme programming](https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it). There is no need to bloat your application with thousands of dependencies. The web is maturing, and like JQuery, axios' time is gradually ending. With current developments, Axios and other popular HTTP client libraries are no longer required to have good developer experience.