npm package: @salespark/http-request
Description: A lightweight TypeScript wrapper around Axios that standardizes all HTTP responses into the global SalesParkContract<T> format, supports global and per-request options, and provides a clean, consistent API for GET/POST/PUT/DELETE requests.
Author: SalesPark
Latest version: 1.0.4

> **npm registry notice:** On **2 May 2026** (timezone **Europe/Lisbon**), this package will no longer be **publicly** installable from the npm registry and will become **restricted to the SalesPark npm organization**. Until then, already-published versions remain public. **No further public releases** or support for external consumers is planned — if you depend on this package, **fork** before that date.

# SalesPark HTTP Request Client - Documentation

## @salespark/http-request

A lightweight TypeScript wrapper around Axios that standardizes all HTTP responses into the global SalesParkContract<T> format, supports global and per-request options, and provides a clean, consistent API for GET/POST/PUT/DELETE requests.

---

## 🧭 Overview

`@salespark/http-request` is a minimalist HTTP client built on top of **Axios**, designed to provide a consistent response format across all HTTP operations. It enforces the `SalesParkContract<T>` response model (`{ status: boolean, data: T }`), never throws exceptions, and includes built-in global header management.

This package is part of the **SalesPark Libraries** ecosystem and follows the same patterns and conventions used across all SalesPark packages.

---

## 📦 Installation

```bash
yarn add @salespark/http-request
# or
npm install @salespark/http-request
```

---

## 🚀 Quick Start

```typescript
import { HttpClient } from '@salespark/http-request';

// Initialize the client
const httpClient = new HttpClient({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
});

// Make requests - all return SalesParkContract<T>
const user = await httpClient.get('/users/1');
if (user.status) {
  console.log('User:', user.data);
} else {
  console.error('Error:', user.data);
}

// Create a new resource
const newPost = await httpClient.post('/posts', {
  title: 'Hello World',
  body: 'My first post'
});

if (newPost.status) {
  console.log('Created post with ID:', newPost.data.id);
}
```

---

## ⚙️ Configuration Options

The `HttpClient` constructor accepts the following options:

| Option    | Type                        | Description                           | Default |
| --------- | --------------------------- | ------------------------------------- | ------- |
| `baseURL` | `string`                    | Base URL for all requests             | -       |
| `timeout` | `number`                    | Request timeout in milliseconds       | `15000` |
| `headers` | `Record<string, string>`    | Default headers for all requests      | `{}`    |

---

## 🧩 Available Methods

All methods return a **Promise** that resolves to the `SalesParkContract<T>` format:

```typescript
interface SalesParkContract<T = any> {
  status: boolean;
  data: T;
}
```

### 🔹 HTTP Methods

| Method                                   | Description                        | Example                                              |
| ---------------------------------------- | ---------------------------------- | ---------------------------------------------------- |
| `get<T>(url, options?)`                  | Execute GET request                | `httpClient.get<User>('/users/1')`                  |
| `post<T>(url, body?, options?)`          | Execute POST request               | `httpClient.post('/users', { name: 'John' })`       |
| `put<T>(url, body?, options?)`           | Execute PUT request                | `httpClient.put('/users/1', { name: 'Jane' })`      |
| `delete<T>(url, options?)`               | Execute DELETE request             | `httpClient.delete('/users/1')`                     |
| `setHeader(key, value)`                  | Set/update global header           | `httpClient.setHeader('Authorization', 'Bearer ...')` |

### 🔹 Request Options

All HTTP methods accept optional `RequestOptions` (extends Axios `AxiosRequestConfig`):

```typescript
interface RequestOptions extends AxiosRequestConfig {
  params?: any;
  headers?: Record<string, string>;
  timeout?: number;
  // ... other Axios options
}
```

---

## 🧠 Detailed Usage Examples

### Basic GET Request

```typescript
import { HttpClient } from '@salespark/http-request';

const client = new HttpClient({
  baseURL: 'https://jsonplaceholder.typicode.com'
});

// Fetch a single user
const user = await client.get('/users/1');
if (user.status) {
  console.log('User name:', user.data.name);
  console.log('User email:', user.data.email);
} else {
  console.error('Failed to fetch user:', user.data);
}
```

### GET with Query Parameters

```typescript
// Fetch posts with query parameters
const posts = await client.get('/posts', {
  params: {
    userId: 1,
    _limit: 5
  }
});

if (posts.status) {
  console.log(`Found ${posts.data.length} posts`);
  posts.data.forEach(post => console.log(post.title));
}
```

### POST Request - Creating Resources

```typescript
// Create a new post
const newPost = await client.post('/posts', {
  title: 'My New Post',
  body: 'This is the content of my post',
  userId: 1
});

if (newPost.status) {
  console.log('Created post with ID:', newPost.data.id);
} else {
  console.error('Failed to create post:', newPost.data);
}
```

### PUT Request - Updating Resources

```typescript
// Update an existing post
const updatedPost = await client.put('/posts/1', {
  id: 1,
  title: 'Updated Post Title',
  body: 'Updated content',
  userId: 1
});

if (updatedPost.status) {
  console.log('Post updated successfully');
} else {
  console.error('Update failed:', updatedPost.data);
}
```

### DELETE Request

```typescript
// Delete a post
const deleteResult = await client.delete('/posts/1');

if (deleteResult.status) {
  console.log('Post deleted successfully');
} else {
  console.error('Delete failed:', deleteResult.data);
}
```

### Global Header Management

```typescript
const client = new HttpClient({
  baseURL: 'https://api.example.com'
});

// Set authorization header for all subsequent requests
client.setHeader('Authorization', 'Bearer your-jwt-token');

// Set custom headers
client.setHeader('X-API-Version', 'v1');
client.setHeader('X-Client-ID', 'my-app');

// All requests will now include these headers
const protectedData = await client.get('/protected-endpoint');
```

### Advanced Configuration

```typescript
const client = new HttpClient({
  baseURL: 'https://api.example.com',
  timeout: 30000, // 30 seconds
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Requested-With': 'XMLHttpRequest'
  }
});

// Make request with custom options
const result = await client.get('/data', {
  timeout: 5000, // Override default timeout for this request
  headers: {
    'Cache-Control': 'no-cache' // Additional header for this request
  },
  params: {
    page: 1,
    limit: 20
  }
});
```

---

## 🧱 Response Model

All methods return the standardized `SalesParkContract<T>` format:

### ✅ Success Response
```typescript
{
  status: true,
  data: T // The actual response data from the API
}
```

### ❌ Error Response
```typescript
{
  status: false,
  data: any // The error object/information
}
```

### TypeScript Usage

```typescript
interface User {
  id: number;
  name: string;
  email: string;
}

const userResponse = await client.get<User>('/users/1');

if (userResponse.status) {
  // TypeScript knows userResponse.data is of type User
  console.log(userResponse.data.name);
  console.log(userResponse.data.email);
} else {
  // Handle error case
  console.error('Error:', userResponse.data);
}
```

---

## 🛡️ Error Handling

The client never throws exceptions. All errors are captured and returned in the standardized format:

```typescript
// Network error, timeout, or HTTP error - all handled consistently
const result = await client.get('/non-existent-endpoint');

if (!result.status) {
  // Handle all types of errors uniformly
  console.error('Request failed:', result.data);
  
  // Error data might contain:
  // - Network errors
  // - HTTP status codes (404, 500, etc.)
  // - Timeout errors
  // - Request cancellation
}
```

### Common Error Scenarios

```typescript
// Handle different error types
const response = await client.get('/api/data');

if (!response.status) {
  const error = response.data;
  
  if (error.code === 'NETWORK_ERROR') {
    console.log('Check your internet connection');
  } else if (error.code === 'TIMEOUT') {
    console.log('Request timed out');
  } else if (error.response?.status === 404) {
    console.log('Resource not found');
  } else if (error.response?.status === 401) {
    console.log('Unauthorized - check your authentication');
  } else {
    console.log('Unexpected error:', error.message);
  }
}
```

---

## 🧪 Testing

The package includes comprehensive tests using Jest and real API calls to JSONPlaceholder:

```bash
# Run tests
yarn test

# Run tests in watch mode
yarn test:watch

# Run tests with coverage
yarn test:coverage
```

### Test Coverage

- ✅ Constructor initialization
- ✅ GET requests (single resources, collections, query parameters)  
- ✅ POST requests (create resources, comments)
- ✅ PUT requests (update resources)
- ✅ DELETE requests
- ✅ Global header management
- ✅ Error handling (network errors, timeouts, 404s)
- ✅ Response standardization
- ✅ Complete CRUD operations

---

## 🏷️ TypeScript Support

The package is written in TypeScript and provides full type safety:

```typescript
import { HttpClient, SalesParkContract } from '@salespark/http-request';

// Fully typed client
const client = new HttpClient({
  baseURL: 'https://api.example.com',
  timeout: 10000
});

// Typed responses
interface Product {
  id: number;
  name: string;
  price: number;
}

const product: SalesParkContract<Product> = await client.get<Product>('/products/1');

if (product.status) {
  // TypeScript knows product.data is of type Product
  console.log(`${product.data.name} costs $${product.data.price}`);
}
```

---

## 📋 API Reference

### Class: `HttpClient`

#### Constructor
```typescript
constructor(options?: HttpClientOptions)
```

#### Methods

**`get<T>(url: string, options?: RequestOptions): Promise<SalesParkContract<T>>`**
- Execute GET request
- Returns typed response wrapped in SalesParkContract

**`post<T>(url: string, body?: any, options?: RequestOptions): Promise<SalesParkContract<T>>`**  
- Execute POST request with optional body
- Returns typed response wrapped in SalesParkContract

**`put<T>(url: string, body?: any, options?: RequestOptions): Promise<SalesParkContract<T>>`**
- Execute PUT request with optional body  
- Returns typed response wrapped in SalesParkContract

**`delete<T>(url: string, options?: RequestOptions): Promise<SalesParkContract<T>>`**
- Execute DELETE request
- Returns typed response wrapped in SalesParkContract

**`setHeader(key: string, value: string): void`**
- Set or update a global header that will be sent with all subsequent requests

### Interfaces

```typescript
interface HttpClientOptions {
  baseURL?: string;
  timeout?: number;
  headers?: Record<string, string>;
}

interface RequestOptions extends AxiosRequestConfig {
  // Inherits all Axios request configuration options
}

interface SalesParkContract<T = any> {
  status: boolean;
  data: T;
}
```

---

## 🔄 Integration with Other SalesPark Packages

This package follows the SalesPark ecosystem patterns and works seamlessly with:

- **@salespark/toolkit** - Utility functions for data processing
- **@salespark/api-client** - Higher-level API client for React applications  
- **@salespark/mongo-repo-utils** - MongoDB utilities for backend services

### Example with @salespark/toolkit

```typescript
import { HttpClient } from '@salespark/http-request';
import { debounce, formatCurrency } from '@salespark/toolkit';

const client = new HttpClient({ 
  baseURL: 'https://api.example.com' 
});

// Debounced search function
const searchProducts = debounce(async (query: string) => {
  const result = await client.get('/products/search', {
    params: { q: query }
  });
  
  if (result.status) {
    return result.data.map(product => ({
      ...product,
      formattedPrice: formatCurrency(product.price)
    }));
  }
  return [];
}, 300);
```

---

## 🛠️ Support

Got stuck? Don't panic — we've got you covered.

### 🤖 AI Assistant

We built a custom **AI Assistant** trained _only_ on `@salespark/http-request`.  
It answers implementation and troubleshooting questions in real time:

👉 Ask the HTTP Request Client GPT:  
https://chatgpt.com/g/g-[YOUR-GPT-ID]-salespark-http-request

_(Free to use with a ChatGPT account)_

---

### 🔒 Internal Usage Notice

This package is primarily designed and maintained for internal use within the SalesPark ecosystem.
While it can technically be used in other TypeScript/JavaScript projects, no official support or guarantees are provided outside of SalesPark-managed projects.

All code follows the same engineering standards applied across the SalesPark platform, ensuring consistency, reliability, and long-term maintainability of our internal systems.

⚡ Note: This package is most efficient and works best when used together with other official SalesPark packages, where interoperability and optimizations are fully leveraged.

Disclaimer: This software is provided "as is", without warranties of any kind, express or implied. SalesPark shall not be held liable for any issues, damages, or losses arising from its use outside the intended SalesPark environment.

Organization packages: https://www.npmjs.com/org/salespark

---

## 📄 License

MIT © [SalesPark](https://salespark.io)

---

_Document version: 1_  
_Last update: 13-11-2025_