Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
with:
run: node ./bin/pr.js
- name: Create pull request
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
id: cpr
with:
branch: release
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sponsors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
echo "$CONTENT"
- name: Create pull request
if: ${{ steps.sponsors.outputs.changed == 'true'}}
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
id: cpr
with:
branch: sponsors
Expand Down
6 changes: 5 additions & 1 deletion ECOSYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ This is a list of axios related libraries and resources. If you have a suggestio
* [axios-api-versioning](https://weffe.github.io/axios-api-versioning) - Add easy to manage api versioning to axios
* [axios-data-unpacker](https://github.com/anubhavsrivastava/axios-data-unpacker) - Axios interceptor that unpacks HTTP responses so that you can focus on actual server data.
* [r2curl](https://github.com/uyu423/r2curl) - Extracts the cURL command string from the Axios object. (AxiosResponse, AxiosRequestConfig)
* [swagger-taxos-codegen](https://github.com/michalzaq12/swagger-taxos-codegen) - Axios based Swagger Codegen (tailored for typescript)
* [axios-endpoints](https://github.com/renancaraujo/axios-endpoints) - Axios endpoints help you to create a more concise endpoint mapping with axios.
* [axios-multi-api](https://github.com/MattCCC/axios-multi-api) - Easy API handling whenever there are many endpoints to add. It helps to make Axios requests in an easy and declarative manner.
* [axios-url-template](https://github.com/rafw87/axios-url-template) - Axios interceptor adding support for URL templates.

### API clients

* [@hey-api/openapi-ts](https://heyapi.dev/openapi-ts/clients/axios) - The OpenAPI to TypeScript codegen. Generate clients, SDKs, validators, and more.
* [swagger-taxos-codegen](https://github.com/michalzaq12/swagger-taxos-codegen) - Axios based Swagger Codegen (tailored for typescript)
* [zodios](https://www.zodios.org) - Typesafe API client based on axios

### Logging and debugging
Expand Down
53 changes: 47 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
</td></tr><tr width="33.333333333333336%"><td align="center" width="33.333333333333336%"> <a href="https://route4me.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;sponsorlist&amp;utm_campaign&#x3D;sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <picture> <source width="200px" height="51px" media="(prefers-color-scheme: dark)" srcset="https://axios-http.com/assets/sponsors/route4me_white.png"> <img width="200px" height="51px" src="https://axios-http.com/assets/sponsors/route4me.png" alt="Route4Me"/> </picture> </a> <p align="center" title="Best Route Planning And Route Optimization Software">Best Route Planning And Route Optimization Software</p> <p align="center"> <a href="https://route4me.com/platform/route-optimization-software?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>Explore</b></a> | <a href="https://route4me.com/platform/marketplace/pricing?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>Free Trial</b></a> | <a href="https://route4me.com/contact?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>Contact</b></a> </p>
</td><td align="center" width="33.333333333333336%"> <a href="https://buzzoid.com/buy-instagram-followers/?utm_source&#x3D;axios&amp;utm_medium&#x3D;sponsorlist&amp;utm_campaign&#x3D;sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="62px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/e1625cb54e10ee40180c99d1495a462e9d6664a4.png" alt="Buzzoid - Buy Instagram Followers"/> </a> <p align="center" title="At Buzzoid, you can buy Instagram followers quickly, safely, and easily with just a few clicks. Rated world&#x27;s #1 IG service since 2012.">At Buzzoid, you can buy Instagram followers quickly, safely, and easily with just a few clicks. Rate...</p> <p align="center"> <a href="https://buzzoid.com/buy-instagram-followers/?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>buzzoid.com</b></a> </p>
</td><td align="center" width="33.333333333333336%"> <a href="https://poprey.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;sponsorlist&amp;utm_campaign&#x3D;sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="70px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/e699ec99f7df3a203ddbc49d3c7712a907e628ea.png" alt="Poprey - Buy Instagram Likes"/> </a> <p align="center" title="Buy Instagram Likes">Buy Instagram Likes</p> <p align="center"> <a href="https://poprey.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>poprey.com</b></a> </p>
</td></tr><tr width="33.333333333333336%"><td align="center" width="33.333333333333336%"> <a href="https://requestly.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;sponsorlist&amp;utm_campaign&#x3D;sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="71px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/16450b4dc0deb9dab5a511bf2bc8b8b4ac33412f.png" alt="Requestly"/> </a> <p align="center" title="A lightweight open-source API Development, Testing &amp; Mocking platform">A lightweight open-source API Development, Testing &amp; Mocking platform</p> <p align="center"> <a href="https://requestly.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>requestly.com</b></a> </p>
</td><td align="center" width="33.333333333333336%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
</td></tr><tr width="33.333333333333336%"><td align="center" width="33.333333333333336%"> <a href="https://betking.com.ua/sports-book/?utm_source&#x3D;axios&amp;utm_medium&#x3D;sponsorlist&amp;utm_campaign&#x3D;sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="70px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/6767b3891180eb94f442953d450a5c121ab8edf6.jpg" alt="Букмекер"/> </a> <p align="center" title="Ставки на спорт, БК в Україні">Ставки на спорт, БК в Україні</p> <p align="center"> <a href="https://betking.com.ua/sports-book/?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>betking.com.ua</b></a> </p>
</td><td align="center" width="33.333333333333336%"> <a href="https://requestly.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;sponsorlist&amp;utm_campaign&#x3D;sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="71px" height="70px" src="https://axios-http.com/assets/sponsors/opencollective/16450b4dc0deb9dab5a511bf2bc8b8b4ac33412f.png" alt="Requestly"/> </a> <p align="center" title="A lightweight open-source API Development, Testing &amp; Mocking platform">A lightweight open-source API Development, Testing &amp; Mocking platform</p> <p align="center"> <a href="https://requestly.com/?utm_source&#x3D;axios&amp;utm_medium&#x3D;readme_sponsorlist&amp;utm_campaign&#x3D;sponsorship" target="_blank"><b>requestly.com</b></a> </p>
</td><td align="center" width="33.333333333333336%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
</td></tr></table>

Expand Down Expand Up @@ -65,6 +65,7 @@
- [Interceptors](#interceptors)
- [Multiple Interceptors](#multiple-interceptors)
- [Handling Errors](#handling-errors)
- [Handling Timeouts](#handling-timeouts)
- [Cancellation](#cancellation)
- [AbortController](#abortcontroller)
- [CancelToken 👎](#canceltoken-deprecated)
Expand Down Expand Up @@ -188,13 +189,13 @@ const axios = require('axios/dist/browser/axios.cjs'); // browser commonJS bundl
Using jsDelivr CDN (ES5 UMD browser module):

```html
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.7/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@1.13.2/dist/axios.min.js"></script>
```

Using unpkg CDN:

```html
<script src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
<script src="https://unpkg.com/axios@1.13.2/dist/axios.min.js"></script>
```

## Example
Expand Down Expand Up @@ -921,6 +922,27 @@ axios.get('/user/12345')
});
```

## Handling Timeouts

```js
async function fetchWithTimeout() {
try {
const response = await axios.get('https://example.com/data', {
timeout: 5000 // 5 seconds
});

console.log('Response:', response.data);

} catch (error) {
if (axios.isAxiosError(error) && error.code === 'ECONNABORTED') {
console.error('❌ Request timed out!');
} else {
console.error('❌ Error:', error.message);
}
}
}
```

## Cancellation

### AbortController
Expand Down Expand Up @@ -1082,7 +1104,7 @@ The server will handle it as:
If your backend body-parser (like `body-parser` of `express.js`) supports nested objects decoding, you will get the same object on the server-side automatically

```js
var app = express();
const app = express();

app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

Expand All @@ -1098,7 +1120,7 @@ If your backend body-parser (like `body-parser` of `express.js`) supports nested

### FormData

To send the data as a `multipart/formdata` you need to pass a formData instance as a payload.
To send the data as a `multipart/form-data` you need to pass a formData instance as a payload.
Setting the `Content-Type` header is not required as Axios guesses it based on the payload type.

```js
Expand Down Expand Up @@ -1778,6 +1800,25 @@ If use ESM, your settings should be fine.
If you compile TypeScript to CJS and you can’t use `"moduleResolution": "node 16"`, you have to enable `esModuleInterop`.
If you use TypeScript to type check CJS JavaScript code, your only option is to use `"moduleResolution": "node16"`.


You can also create a custom instance with typed interceptors:

```typescript
import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios';

const apiClient: AxiosInstance = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
});

apiClient.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// Add auth token
return config;
}
);
```

## Online one-click setup

You can use Gitpod, an online IDE(which is free for Open Source) for contributing or running the examples online.
Expand Down
6 changes: 3 additions & 3 deletions bin/actions/notify_published.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import fs from 'fs/promises';
const argv = minimist(process.argv.slice(2));
console.log(argv);

let {tag} = argv;
let { tag } = argv;

(async() => {
(async () => {
if (!tag || tag === true) {
const {version} = JSON.parse((await fs.readFile('./package.json')).toString());
const { version } = JSON.parse((await fs.readFile('./package.json')).toString());

tag = 'v' + version;
} else if (typeof tag !== 'string') {
Expand Down
132 changes: 132 additions & 0 deletions examples/abort-controller/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<!doctype html>
<html>
<head>
<title>axios - abort controller example</title>
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"/>
<style>
.status { margin-top: 10px; }
</style>
</head>
<body class="container">
<h1>axios.AbortController</h1>

<div class="row" style="margin-top: 20px;">
<div class="col-md-12">
<h3>1. Single Request Cancellation</h3>
<p>Click "Start Request" to begin a 3-second request. Click "Cancel Request" to abort it.</p>
<button id="startBtn" class="btn btn-primary">Start Request</button>
<button id="cancelBtn" class="btn btn-danger" disabled>Cancel Request</button>
<div id="singleStatus" class="status"></div>
</div>
</div>

<hr/>

<div class="row" style="margin-top: 20px;">
<div class="col-md-12">
<h3>2. Search-as-you-type (Race Condition Handling)</h3>
<p>Type quickly. Previous pending requests will be cancelled automatically.</p>
<div class="form-group">
<input type="text" id="searchInput" class="form-control" placeholder="Type to search...">
</div>
<div id="searchStatus" class="status"></div>
<ul id="searchLog" class="list-group" style="margin-top: 10px; max-height: 200px; overflow-y: auto;"></ul>
</div>
</div>

<script src="/axios.min.js"></script>
<script>
// -----------------------------------------------------------------------
// 1. Single Request Cancellation
// -----------------------------------------------------------------------
const startBtn = document.getElementById('startBtn');
const cancelBtn = document.getElementById('cancelBtn');
const singleStatus = document.getElementById('singleStatus');

let controller;

startBtn.onclick = function() {
// Create a new AbortController instance for this request
controller = new AbortController();

startBtn.disabled = true;
cancelBtn.disabled = false;
singleStatus.innerHTML = '<span class="text-info">Request pending... (3s delay)</span>';

axios.get('/abort-controller/server?delay=3000', {
signal: controller.signal
})
.then(function (response) {
singleStatus.innerHTML = '<span class="text-success">' + response.data.message + '</span>';
})
.catch(function (err) {
if (axios.isCancel(err)) {
singleStatus.innerHTML = '<span class="text-warning">Request canceled: ' + err.message + '</span>';
} else {
singleStatus.innerHTML = '<span class="text-danger">Error: ' + err.message + '</span>';
}
})
.finally(function () {
startBtn.disabled = false;
cancelBtn.disabled = true;
controller = null;
});
};

cancelBtn.onclick = function() {
if (controller) {
// Abort the request
controller.abort();
}
};


// -----------------------------------------------------------------------
// 2. Search-as-you-type
// -----------------------------------------------------------------------
const searchInput = document.getElementById('searchInput');
const searchStatus = document.getElementById('searchStatus');
const searchLog = document.getElementById('searchLog');

let searchController;

searchInput.addEventListener('input', function(e) {
const query = e.target.value;

if (searchController) {
// Cancel the previous request
searchController.abort();
}

// Create a new controller for the new request
searchController = new AbortController();

log('New search for: "' + query + '"');
searchStatus.innerHTML = '<span class="text-info">Searching...</span>';

axios.get('/abort-controller/server?delay=1000', {
signal: searchController.signal
})
.then(function (response) {
searchStatus.innerHTML = '<span class="text-success">Result for "' + query + '": ' + response.data.message + '</span>';

Check failure

Code scanning / CodeQL

DOM text reinterpreted as HTML High

DOM text
is reinterpreted as HTML without escaping meta-characters.
log('Success: ' + query);
})
.catch(function (err) {
if (axios.isCancel(err)) {
log('Cancelled: ' + query);
} else {
searchStatus.innerHTML = '<span class="text-danger">Error: ' + err.message + '</span>';
log('Error: ' + query);
}
});
});

function log(msg) {
const li = document.createElement('li');
li.className = 'list-group-item py-1';
li.textContent = new Date().toLocaleTimeString() + ' - ' + msg;
searchLog.prepend(li);
}
</script>
</body>
</html>
16 changes: 16 additions & 0 deletions examples/abort-controller/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import url from 'url';

export default function (req, res) {
const parsedUrl = url.parse(req.url, true);
const delay = parsedUrl.query.delay || 3000;

setTimeout(() => {
res.writeHead(200, {
'Content-Type': 'text/json'
});
res.write(JSON.stringify({
message: 'Response completed successfully after ' + delay + 'ms'
}));
res.end();
}, delay);
};
2 changes: 1 addition & 1 deletion examples/get/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const people = [

export default function (req, res) {
res.writeHead(200, {
'Content-Type': 'text/json'
'Content-Type': 'application/json'
});
res.write(JSON.stringify(people));
res.end();
Expand Down
2 changes: 1 addition & 1 deletion examples/post/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function (req, res) {
req.on('end', function () {
console.log('POST data received');
res.writeHead(200, {
'Content-Type': 'text/json'
'Content-Type': 'application/json'
});
res.write(JSON.stringify(data));
res.end();
Expand Down
2 changes: 1 addition & 1 deletion examples/postMultipartFormData/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function (req, res) {
req.on('end', function () {
console.log('POST received');
res.writeHead(200, {
'Content-Type': 'text/json'
'Content-Type': 'application/json'
});
res.end();
});
Expand Down
22 changes: 20 additions & 2 deletions index.d.cts
Original file line number Diff line number Diff line change
Expand Up @@ -515,14 +515,32 @@ declare namespace axios {
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
}

type AxiosRequestInterceptorUse<T> = (onFulfilled?: ((value: T) => T | Promise<T>) | null, onRejected?: ((error: any) => any) | null, options?: AxiosInterceptorOptions) => number;
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
type AxiosInterceptorRejected = (error: any) => any;

type AxiosResponseInterceptorUse<T> = (onFulfilled?: ((value: T) => T | Promise<T>) | null, onRejected?: ((error: any) => any) | null) => number;
type AxiosRequestInterceptorUse<T> = (
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
onRejected?: AxiosInterceptorRejected | null,
options?: AxiosInterceptorOptions
) => number;

type AxiosResponseInterceptorUse<T> = (
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
onRejected?: AxiosInterceptorRejected | null
) => number;

interface AxiosInterceptorHandler<T> {
fulfilled: AxiosInterceptorFulfilled<T>;
rejected?: AxiosInterceptorRejected;
synchronous: boolean;
runWhen?: (config: AxiosRequestConfig) => boolean;
}

interface AxiosInterceptorManager<V> {
use: V extends AxiosResponse ? AxiosResponseInterceptorUse<V> : AxiosRequestInterceptorUse<V>;
eject(id: number): void;
clear(): void;
handlers?: Array<AxiosInterceptorHandler<V>>;
}

interface AxiosInstance extends Axios {
Expand Down
Loading