@axios-extensions/plugins-api
v1.0.7
Published
Solves the missing priority / add / remove interceptors in Axios
Downloads
849
Readme
📖 Table of Contents
📍 Overview
Axios Extensions elevates your experience with Axios, offering a meticulously curated suite of extensions that enhance the capabilities of the popular HTTP client. Designed with modularity at its core, these extensions can be seamlessly integrated individually or in combination, depending on your project's needs.
Built with TypeScript, this project not only enriches your applications with additional functionality but also ensures a type-safe development environment, offering comprehensive type definitions for all plugins. At their essence, each plugin operates as an interceptor, making them universally compatible with any Axios instance. This design choice guarantees a flexible and straightforward API, simplifying the integration process and elevating the overall user experience.
🌟 Key Features
Discover the core functionalities that enhance the flexibility and power of our solution:
- Plugin Prioritization: Control the order in which plugins execute to fine-tune the behavior of your application.
- Seamless Plugin Chaining: Effortlessly link plugins together to extend functionality without compromising performance.
- Dynamic Plugin Management: Add or remove plugins on-the-fly, enabling a customizable and adaptive technology stack.
🛠️ Core Built-in Plugins
Elevate your application with our versatile set of built-in plugins, designed for comprehensive adaptability and robustness:
- Dynamic Base URL: Easily modify the base URL for API calls, allowing for seamless transitions between different environments or endpoints.
- Error Handling: A sophisticated error handler plugin to gracefully manage and respond to errors, ensuring a smooth user experience.
- Adaptive Headers: Dynamically adjust headers for your requests, providing the flexibility to meet various server-side requirements.
- Bearer Token Integration: Secure your API calls with Bearer token authentication, enhancing the security posture of your application.
- Token Refresh Mechanism: Automate token refreshment to maintain uninterrupted service access, ensuring your application remains connected and secure.
🚀 Getting Started
Project Dependencies
Please ensure you have the following dependencies installed in your project before proceeding:
- ℹ️ Axios v1.6+
🔧 Installation
Add to your project using NPM or Yarn:
NPM
npm install @axios-extensions/plugins-api
Yarn
yarn add @axios-extensions/plugins-api
🤖 How to use?
Basic usage
- Create your core
api.ts
file and import the plugins you want to use.
// src/core/api.ts
// Import any plugin you want to use.
import {
HeaderRequestInterceptor,
JwtBearerTokenRequestInterceptor,
createApi,
} from "@axios-extensions/plugins-api";
// Create an instance of Axios with the plugins you want to use.
export const { api, installInterceptor } = createApi({
// Enable/disable the built-in error handler.
enableErrorHandler: true,
// Use undefined if you don't want to use a base URL.
// Uses the built-in base url plugin.
baseURL: () => "https://example.com/api",
interceptors: [
HeaderRequestInterceptor(() => ({ Accept: "application/ld+json" })), // Providing no method = any method.
HeaderRequestInterceptor(
() => ({ "Content-Type": "application/ld+json" }),
"post",
),
HeaderRequestInterceptor(
() => ({ "Content-Type": "application/ld+json" }),
"put",
),
HeaderRequestInterceptor(
() => ({ "Content-Type": "application/merge-patch+json" }),
"patch",
),
JwtBearerTokenRequestInterceptor(
() => "your-token",
["/api/login", "/api/refresh", "/api/excluded-route"],
),
],
});
export default api;
- Use the
api
instance in your application.
// src/example.ts
import api from "./core/api";
// You can use axios as you normally would.
api.get("/images").then((r) => console.log(r.data));
🚀 Dynamically install interceptors
// src/example.ts
import { HeaderRequestInterceptor } from "@axios-extensions/plugins-api";
import { api, installInterceptor } from "./core/api";
// No extra interceptor
api.get("/images").then((r) => console.log(r.data));
// Add an extra interceptor only for get calls
installInterceptor(
HeaderRequestInterceptor(() => ({ "X-Extra-Header": "extra" }), "get"),
);
api.get("/images").then((r) => console.log(r.data));
🛡️ Utilizing the Built-in Error Handler
Note: By default Axios doesn't throw errors for status codes 4xx and 5xx. This plugin will so they can be handled correctly.
Enabling the error handler plugin will automatically return 3 error types:
ClientError
(status code 4xx)ServerError
(status code 5xx)NetworkError
(no response)AxiosError
(default AxiosError) (any other error not caught by the plugin)
- Add
enableErrorHandler
in yourapi.ts
file.
// src/core/api.ts
// ...
// Create an instance of Axios with the plugins you want to use.
export const { api, installInterceptor } = createApi({
// Toggle the built-in error handler.
enableErrorHandler: true,
//...
});
// ...
- Use the
api
instance in your application.
// src/example.ts
import api from "./core/api";
// This will throw an ClientError
api
.get("https://httpstat.us/400")
.then((r) => console.log(r.data))
.catch((e) => {
if (e instanceof ClientError) {
console.log("Client error:", e);
} else if (e instanceof ServerError) {
console.log("Server error:", e);
} else if (e instanceof NetworkError) {
console.log("Network error:", e);
} else {
console.log("Another unknown error:", e);
}
});
The RefreshTokenPlugin is designed to automatically refresh your authentication token upon encountering a 401 status code. This plugin demands special handling and does not follow the standard installation procedure.
Once the token refresh operation concludes, it retries the original request, ensuring a uninterrupted continuation of your request.
// src/core/refreshToken.ts
import {
installInterceptor,
RefreshTokenResponseInterceptor,
api,
} from "./core/api";
const refreshTokenPlugin = RefreshTokenResponseInterceptor(
api, // Include the api instance, leveraging the automatic retry functionality.
() => api.post("/api/refresh", { refreshToken: "your-refresh" }),
["/api/login", "/api/refresh", "/api/excluded-route"],
);
installInterceptor(refreshTokenPlugin);
Note: Priority is used to determine the order in which the plugins are executed. The lower the number, the earlier the plugin is executed.
Example: A plugin with priority -100
will be executed before a plugin with priority 10
.
- Create a new plugin file.
// src/example-request-plugin.ts
import { installInterceptor } from "./core/api";
import type {
InternalAxiosRequestConfig,
AxiosError,
AxiosResponse,
} from "axios";
import { InterceptorType } from "@axios-extensions/plugins-api";
import type { InterceptorConfig } from "@axios-extensions/plugins-api";
export function MyCustomRequestPlugin(
baseUrlGetter: () => string,
): InterceptorConfig<InterceptorType.REQUEST> {
const myState = useSomeState();
async function resolved(
requestConfig: InternalAxiosRequestConfig,
): Promise<InternalAxiosRequestConfig> {
requestConfig.baseURL = myState.baseUrl.value;
return requestConfig;
}
return {
name: "MyCustomRequestPlugin",
type: InterceptorType.REQUEST,
priority: 1,
resolved,
};
}
Note: Priority is used to determine the order in which the plugins are executed. The lower the number, the earlier the plugin is executed.
Example: A plugin with priority -100
will be executed before a plugin with priority 10
.
- Create a new plugin file.
// src/example-response-plugin.ts
import { installInterceptor } from "./core/api";
import type { AxiosError, AxiosResponse } from "axios";
import { InterceptorType } from "@axios-extensions/plugins-api";
import type { InterceptorConfig } from "@axios-extensions/plugins-api";
export function MyCustomRequestPlugin(
baseUrlGetter: () => string,
): InterceptorConfig<InterceptorType.REQUEST> {
const myState = useSomeState();
async function resolved(
response: AxiosResponse,
): Promise<InternalAxiosRequestConfig> {
myState.error.value = "Success!";
return requestConfig;
}
async function rejected(
error: AxiosError,
): Promise<InternalAxiosRequestConfig> {
myState.error.value = error.message;
return requestConfig;
}
return {
name: "MyCustomResponsePlugin",
type: InterceptorType.RESPONSE,
priority: 1,
resolved,
rejected,
};
}
🤝 Contributing
Contributions are welcome! Here are several ways you can contribute:
- Pull Requests: Want to make a contribution to the project? Check out the contibution guidelines.
- Discussions: Share your insights, provide feedback, or ask questions.
- Bug reports: Submit bugs found.
Contributing Guidelines
- Fork the Repository: Start by forking the project repository to your GitHub account.
- Clone Locally: Clone the forked repository to your local machine using a Git client.
git clone <your-forked-repo-url>
- Create a New Branch: Always work on a new branch, giving it a descriptive name.
git switch -b new-feature-x
- Make Your Changes: Develop and test your changes locally.
- Commit Your Changes: Commit with a clear and concise message describing your updates.
git commit -am 'Implemented new feature x.'
- Push to GitHub: Push the changes to your forked repository.
git push origin new-feature-x
- Submit a Pull Request: Create a PR against the original project repository. Clearly describe the changes and their motivations.
Once your PR is reviewed and approved, it will be merged into the main branch.
📄 License
This project is protected under the MIT License. For more details, refer to the LICENSE file.
👏 Acknowledgments
- Axios for providing a simple and flexible HTTP client.