https://github.com/oharu121/axios-fluent
A fluent, type-safe HTTP client wrapper around Axios with method chaining
https://github.com/oharu121/axios-fluent
api axios builder http rest
Last synced: 15 days ago
JSON representation
A fluent, type-safe HTTP client wrapper around Axios with method chaining
- Host: GitHub
- URL: https://github.com/oharu121/axios-fluent
- Owner: oharu121
- License: mit
- Created: 2025-11-07T15:50:03.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-06-08T18:06:00.000Z (18 days ago)
- Last Synced: 2026-06-08T20:07:31.554Z (18 days ago)
- Topics: api, axios, builder, http, rest
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/axios-fluent
- Size: 349 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# axios-fluent
[](https://badge.fury.io/js/axios-fluent)







A fluent, type-safe HTTP client wrapper around Axios with method chaining.
## Features
- Fluent, chainable API for building HTTP requests
- Full TypeScript support with generic typing
- Immutable configuration pattern
- All HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
- **Convenient response extraction** - `.data()`, `.status()`, `.headers()`, `.ok()` methods
- **Enhanced error handling** - Clear, structured error information with `AxonError`
- Built-in authentication helpers (Bearer, Basic)
- Content-Type helpers
- Request/response transformers
- Secure by default (HTTPS certificate validation enabled)
## Installation
```bash
npm install axios-fluent
```
## Importing
```typescript
// Default export (recommended)
import Axon from "axios-fluent";
// Named export (alternative)
import { Axon } from "axios-fluent";
// With error class
import Axon, { AxonError } from "axios-fluent";
```
## Quick Start
```typescript
import Axon from "axios-fluent";
// Create a client
const client = Axon.new();
// Make a simple GET request (backward compatible)
const response = await client.get("https://api.example.com/users");
console.log(response.data);
// Or use .data() for cleaner code (new!)
const users = await client.get("https://api.example.com/users").data();
// Chain configuration methods
const users = await client
.baseUrl("https://api.example.com")
.bearer("your-jwt-token")
.json()
.timeout(5000)
.get("/users")
.data(); // Extract data directly!
```
## API Reference
### Factory Methods
#### `Axon.new(options?: Options): Axon`
Creates a new Axon instance.
**Options:**
- `allowInsecure?: boolean` - Allow self-signed certificates (default: `false`)
```typescript
// Secure by default (production)
const client = Axon.new();
// Allow self-signed certificates (development only)
const devClient = Axon.new({ allowInsecure: true });
```
#### `Axon.dev(): Axon`
Creates a new Axon instance for development with `allowInsecure: true` enabled by default.
```typescript
// Quick development setup - allows self-signed certificates
const client = Axon.dev();
// Equivalent to:
const client = Axon.new({ allowInsecure: true });
```
**⚠️ Warning:** Only use in development/testing environments. This disables SSL certificate verification.
### HTTP Methods
All HTTP methods return an `AxonResponse` wrapper that:
- Is awaitable (backward compatible - returns full `AxiosResponse`)
- Provides convenient methods: `.data()`, `.status()`, `.headers()`, `.ok()`
- Supports full TypeScript generic typing
#### `get(url: string): AxonResponse`
```typescript
interface User {
id: number;
name: string;
}
// Backward compatible - get full response
const response = await client.get("/api/user/123");
console.log(response.data.name); // Type-safe access
// New - get data directly (recommended)
const user = await client.get("/api/user/123").data();
console.log(user.name); // Cleaner code!
// Get just the status code
const status = await client.get("/api/user/123").status(); // 200
// Check if request succeeded
const isOk = await client.get("/api/user/123").ok(); // true
```
#### `post(url: string, payload?: any): Promise>`
```typescript
const newUser = { name: "John Doe", email: "john@example.com" };
const response = await client.post("/api/users", newUser);
```
#### `put(url: string, payload?: any): Promise>`
```typescript
const updates = { name: "Jane Doe" };
await client.put("/api/user/123", updates);
```
#### `patch(url: string, payload?: any): Promise>`
```typescript
await client.patch("/api/user/123", { email: "new@example.com" });
```
#### `delete(url: string, payload?: any): Promise>`
```typescript
await client.delete("/api/user/123");
```
#### `head(url: string): Promise>`
```typescript
const response = await client.head("/api/resource");
console.log(response.headers);
```
#### `options(url: string): Promise>`
```typescript
const response = await client.options("/api/resource");
```
### Response Convenience Methods
All HTTP methods return an `AxonResponse` wrapper with these convenient methods:
#### `.data(): Promise`
Extracts only the response data, discarding status, headers, etc.
```typescript
// Instead of:
const response = await client.get('/users');
const users = response.data;
// You can now do:
const users = await client.get('/users').data();
```
#### `.status(): Promise`
Extracts only the HTTP status code.
```typescript
const statusCode = await client.get('/users').status();
console.log(statusCode); // 200
```
#### `.headers(): Promise`
Extracts only the response headers.
```typescript
const headers = await client.get('/users').headers();
console.log(headers['content-type']);
```
#### `.ok(): Promise`
Checks if the response status is in the 2xx range (success).
```typescript
const isSuccessful = await client.delete('/users/123').ok();
if (isSuccessful) {
console.log('User deleted successfully');
}
```
### Enhanced Error Handling
Errors are automatically wrapped in `AxonError` with 5 essential properties for debugging:
```typescript
import Axon, { AxonError } from 'axios-fluent';
try {
await client.get('/api/users').data();
} catch (error) {
if (error instanceof AxonError) {
// 5 essential properties for error handling
console.log('Status:', error.status); // 404
console.log('Status Text:', error.statusText); // 'Not Found'
console.log('URL:', error.url); // '/api/users'
console.log('Method:', error.method); // 'GET'
console.log('Response:', error.responseData); // Error body
// Formatted error message
console.log(error.toString());
// AxonError: Request failed with status code 404
// Request: GET /api/users
// Status: 404 Not Found
// Response: {"message":"Users not found"}
}
}
```
**AxonError Properties:**
- `status` - HTTP status code (404, 500, etc.)
- `statusText` - Human-readable status text
- `url` - Request URL
- `method` - HTTP method (GET, POST, etc.)
- `responseData` - Error response body
### Configuration Methods
All configuration methods return a new Axon instance, making them chainable.
#### `baseUrl(url: string): Axon`
Sets the base URL for all requests.
```typescript
const client = Axon.new().baseUrl("https://api.example.com");
await client.get("/users"); // Requests https://api.example.com/users
```
#### `timeout(ms: number): Axon`
Sets request timeout in milliseconds.
```typescript
const client = Axon.new().timeout(5000); // 5 second timeout
```
### Authentication
#### `bearer(token: string): Axon`
Sets Bearer token authentication.
```typescript
const client = Axon.new().bearer("your-jwt-token").get("/api/protected");
```
#### `basic(token: string): Axon`
Sets Basic authentication.
```typescript
const credentials = btoa("username:password");
const client = Axon.new().basic(credentials);
```
### Headers
#### `setHeader(key: string, value: string): Axon`
Sets a custom header.
```typescript
const client = Axon.new()
.setHeader("X-API-Key", "secret")
.setHeader("X-Custom-Header", "value");
```
### Content-Type Helpers
#### `json(): Axon`
Sets `Content-Type: application/json`.
```typescript
const client = Axon.new().json();
```
#### `multipart(): Axon`
Sets `Content-Type: multipart/form-data`.
```typescript
const formData = new FormData();
formData.append("file", fileBlob);
const client = Axon.new().multipart();
await client.post("/upload", formData);
```
#### `encodeUrl(): Axon`
Sets `Content-Type: application/x-www-form-urlencoded`.
```typescript
const client = Axon.new().encodeUrl();
```
#### `octet(): Axon`
Sets `Content-Type: application/octet-stream`.
```typescript
const client = Axon.new().octet();
```
### Query Parameters
#### `params(params: object): Axon`
Sets query parameters.
```typescript
const client = Axon.new().params({ page: 1, limit: 10 });
await client.get("/api/users"); // Requests /api/users?page=1&limit=10
```
### Advanced Configuration
#### `length(contentLength: number): Axon`
Sets the `Content-Length` header.
```typescript
const client = Axon.new().length(1024);
```
#### `digest(digest: string): Axon`
Sets the `Digest` header for content integrity.
```typescript
const client = Axon.new().digest("sha256-hash");
```
#### `range(offset: number, end: number, fileSize: number): Axon`
Sets the `Content-Range` header for partial uploads.
```typescript
const client = Axon.new().range(0, 1024, 10240);
```
#### `transformRequest(transformers: AxiosRequestTransformer | AxiosRequestTransformer[]): Axon`
Sets custom request transformers.
```typescript
const client = Axon.new().transformRequest((data, headers) => {
// Transform request data
return data;
});
```
#### `responseType(responseType: ResponseType): Axon`
Sets the expected response type.
```typescript
const client = Axon.new().responseType("blob");
const response = await client.get("/download/file.pdf");
```
## Examples
### Basic API Client
```typescript
import Axon from "axios-fluent";
const api = Axon.new()
.baseUrl("https://api.example.com")
.bearer("your-jwt-token")
.json()
.timeout(10000);
// Fetch users - using .data() for cleaner code
const users = await api.get("/users").data();
// Create a new user
const newUser = await api.post("/users", {
name: "John Doe",
email: "john@example.com",
}).data();
// Update user
await api.put(`/users/${newUser.id}`, {
name: "Jane Doe",
});
// Delete user and check if successful
const deleted = await api.delete(`/users/${newUser.id}`).ok();
console.log('Deleted:', deleted);
```
### File Upload
```typescript
import Axon from "axios-fluent";
import FormData from "form-data";
const formData = new FormData();
formData.append("file", fileBlob);
formData.append("name", "document.pdf");
const response = await Axon.new()
.baseUrl("https://api.example.com")
.bearer("token")
.multipart()
.post("/upload", formData);
```
### Download File
```typescript
import Axon from "axios-fluent";
import fs from "fs";
const response = await Axon.new()
.responseType("blob")
.get("https://example.com/file.pdf");
fs.writeFileSync("file.pdf", response.data);
```
### Error Handling
```typescript
import Axon, { AxonError } from "axios-fluent";
try {
const users = await Axon.new()
.bearer("token")
.get("https://api.example.com/users")
.data();
console.log(users);
} catch (error) {
// AxonError provides convenient access to error details
if (error instanceof AxonError) {
console.error("Status:", error.status); // 404
console.error("URL:", error.url); // https://api.example.com/users
console.error("Method:", error.method); // GET
console.error("Response:", error.responseData);// Error body
// Formatted error message with all details
console.error(error.toString());
// Handle specific status codes
if (error.status === 401) {
console.log("Unauthorized - refresh token");
} else if (error.status >= 500) {
console.log("Server error - retry later");
}
}
}
```
### Pagination
```typescript
import Axon from "axios-fluent";
async function fetchAllUsers() {
const client = Axon.new().baseUrl("https://api.example.com").bearer("token");
let page = 1;
let allUsers = [];
while (true) {
// Use .data() for cleaner code
const response = await client
.params({ page, limit: 100 })
.get<{ users: User[]; hasMore: boolean }>("/users")
.data();
allUsers.push(...response.users);
if (!response.hasMore) break;
page++;
}
return allUsers;
}
```
## Security
### HTTPS Certificate Validation
By default, Axon validates HTTPS certificates. This is the recommended behavior for production environments.
```typescript
// Secure by default
const client = Axon.new();
```
### Self-Signed Certificates (Development Only)
For development or testing environments with self-signed certificates, use the `dev()` factory method:
```typescript
// Development only - NOT for production
const devClient = Axon.dev();
// Or use the explicit option
const devClient = Axon.new({ allowInsecure: true });
```
This disables SSL certificate verification and makes your application vulnerable to man-in-the-middle attacks.
## TypeScript
Axon is written in TypeScript and provides full type definitions.
```typescript
interface ApiResponse {
data: T;
message: string;
}
interface User {
id: number;
name: string;
email: string;
}
const response = await Axon.new().get>("/api/user/123");
// Fully typed response
console.log(response.data.data.name); // TypeScript knows the shape
```
## License
MIT
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.
## Support
If you encounter any issues, please file a bug report on the GitHub repository.