npm package: @libs-ui/services-http-request
Description: Service trung gian cho HTTP requests trong Angular. Gọi bất kỳ method nào của một service khác thông qua config object, hỗ trợ caching 3 tầng (memory / localStorage / IndexedDB) và auto-detect Observable vs Promise. Kèm bộ **API Mockup** (`returnListObjec
Latest version: 0.2.356-23

# Http Request Service

Service trung gian cho HTTP requests trong Angular. Gọi bất kỳ method nào của một service khác thông qua config object, hỗ trợ caching 3 tầng (memory / localStorage / IndexedDB) và auto-detect Observable vs Promise. Kèm bộ **API Mockup** (`returnListObject`, `returnDetailObject`) để phát triển frontend không cần backend.

## Tính năng

- ✅ `callApi()` — gọi method bất kỳ của service qua config, không cần inject trực tiếp
- ✅ Caching 3 tầng: `service` (memory Map) / `local-store` (localStorage) / `indexDB` (persist + TTL)
- ✅ Auto-detect Observable/Promise — không cần convert thủ công
- ✅ `convertResponseData` — transform response trước khi trả về (cache lưu raw)
- ✅ `updateArguments()` — tự động cập nhật page params cho infinite scroll / load more
- ✅ **API Mockup**: `returnListObject`, `returnDetailObject`, `getConfigListDataDemo`, `pagingToList`

## Cài đặt

```bash
npm install @libs-ui/services-http-request
```

## Import

```typescript
// Service chính
import { LibsUiHttpRequestService } from '@libs-ui/services-http-request';

// API Mockup (dev/test)
import { returnListObject, returnDetailObject, getConfigListDataDemo, pagingToList } from '@libs-ui/services-http-request';
```

## Quick Start — callApi()

```typescript
import { Component, inject } from '@angular/core';
import { LibsUiHttpRequestService } from '@libs-ui/services-http-request';

@Component({ standalone: true, ... })
export class FeatureComponent {
  private httpReq = inject(LibsUiHttpRequestService);

  async loadData() {
    // Gọi UserService.getUsers(page=1) — không cần inject UserService
    const result = await this.httpReq.callApi<IHttpResponse<User[]>>({
      serviceClass: UserService,   // Angular DI resolve tự động
      functionName: 'getUsers',    // ten method
      argumentsValue: [1],         // arguments truyền vào method
    });
    console.log(result.data); // User[]
  }
}
```

## Caching

```typescript
// 3 loại cache: service (memory) | local-store (localStorage) | indexDB (persist + TTL)
const result = await httpReq.callApi({
  serviceClass: UserService,
  functionName: 'getUsers',
  argumentsValue: [],
  keyCache: 'USER_LIST_UNIQUE_KEY', // UUID cố định — KHÔNG random
  cacheType: 'service', // memory, nhanh nhất
  // cacheType: 'local-store',        // persist qua session
  // cacheType: 'indexDB',            // persist + timeCache phút
  timeCache: 30, // 30 phút (chỉ áp dụng cho indexDB)
  clearCache: false, // true = xóa cache trước khi gọi
});
```

## API Mockup — Dev Mode

```typescript
import { returnListObject, returnDetailObject } from '@libs-ui/services-http-request';
import { UtilsHttpParamsRequest } from '@libs-ui/utils';

const mockData = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
];

// List với phân trang
const listSvc = returnListObject(mockData, undefined, { delay: 300 });
const params = new UtilsHttpParamsRequest({ fromObject: { page: '1', per_page: '10' } });
const paged = await listSvc.listPaging(params);
// → { code: 200, data: [...], paging: { page, total_pages, total_items, per_page } }

// Detail lookup by key
const detailParams = new UtilsHttpParamsRequest({ fromObject: { keys: '1', fieldKey: 'id' } });
const detailSvc = returnDetailObject(detailParams, mockData);
const detail = await detailSvc.detailByData();
// → { code: 200, data: { id: 1, name: 'Alice' } }
```

## Infinite Scroll — updateArguments()

```typescript
let argumentsValue = [new HttpParams().set('page', '1').set('per_page', '20')];
let pagingStore: IPaging;
let isLoadedAll = false;

async function loadMore() {
  isLoadedAll = httpReq.updateArguments(
    argumentsValue,
    { paging: pagingStore },
    pagingStore,
    searchKeyword,
    true,
    isLoadedAll,
  );

  if (!isLoadedAll) {
    const res = await httpReq.callApi({ ..., argumentsValue });
    pagingStore = res.paging;
  }
}
```

## API — Public Methods

| Method                                                                | Returns               | Mô tả                                                                |
| --------------------------------------------------------------------- | --------------------- | -------------------------------------------------------------------- |
| `callApi<T>(config)`                                                  | `Promise<T>`          | Gọi method của service theo config, có cache tự động                 |
| `updateArguments(args, data, paging, search, online, loaded, guide?)` | `boolean`             | Cập nhật argumentsValue cho load more. Trả về `true` khi hết dữ liệu |
| `fakeResponsePagingApi()`                                             | `{ paging: IPaging }` | Tạo fake paging (fallback) — `page:0, total_pages:1`                 |

## API — IHttpRequestConfig

| Field                 | Type                                      | Required                | Mô tả                                      |
| --------------------- | ----------------------------------------- | ----------------------- | ------------------------------------------ |
| `serviceClass`        | `Type<T>`                                 | Một trong hai           | Class service — Angular DI resolve tự động |
| `objectInstance`      | `T`                                       | Một trong hai           | Object instance — không qua DI             |
| `functionName`        | `keyof T`                                 | ✅                      | Tên method cần gọi                         |
| `argumentsValue`      | `Array<any>`                              | ✅                      | Arguments truyền vào method                |
| `cacheType`           | `'service' \| 'local-store' \| 'indexDB'` | ❌                      | Loại cache                                 |
| `keyCache`            | `string`                                  | Bắt buộc nếu dùng cache | Cache key (UUID cố định)                   |
| `timeCache`           | `number`                                  | ❌                      | Phút — chỉ áp dụng cho `indexDB`           |
| `clearCache`          | `boolean`                                 | ❌                      | Xóa cache trước khi gọi                    |
| `convertResponseData` | `(res) => any`                            | ❌                      | Transform response trước khi trả về        |

## API Mockup Functions

| Function                                       | Returns                                | Mô tả                                             |
| ---------------------------------------------- | -------------------------------------- | ------------------------------------------------- |
| `returnListObject(data?, fn?, opts?)`          | `{ list, listObservable, listPaging }` | Mock list API từ array tĩnh hoặc dynamic function |
| `returnDetailObject(params, data?, fn?, ...)`  | `{ detailByData, detailByFunction }`   | Mock detail API — lookup theo key                 |
| `getConfigListDataDemo(params?, schema?, fn?)` | `{ list, detailByData }`               | Tạo 3015 items mock sẵn                           |
| `pagingToList(data, page, perPage)`            | `IHttpResponse<T>`                     | Phân trang mảng data                              |

## Lưu ý quan trọng

- **`keyCache` phải là UUID cố định** — không dùng biến ngẫu nhiên hay timestamp. Cùng key = cache hit.
- **`serviceClass` vs `objectInstance`**: dùng `serviceClass` khi service được DI quản lý; `objectInstance` khi cần mock hoặc service không injectable.
- **Cache key** được tạo từ `keyCache + MD5(argumentsValue)` — cùng `keyCache` nhưng args khác = cache key khác.
- **Observable auto-wrap**: method có thể trả về Observable hay Promise — service tự detect và wrap bằng `lastValueFrom()`.
- **`convertResponseData`** chạy cả khi đọc từ cache — cache luôn lưu raw response.