@libs-ui/services-base-request-abstract 0.2.355-8 → 0.2.356-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +211 -2
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,3 +1,212 @@
1
- # services-base-request-abstract
1
+ # Base Request Abstract Service
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ Abstract base class cung cấp toàn bộ infrastructure cho HTTP requests trong Angular: GET, POST, PUT, PATCH, DELETE, file upload với progress tracking, response normalization, error handling tự động, caching với IndexedDB và page zero conversion.
4
+
5
+ ## Tính năng
6
+
7
+ - ✅ HTTP methods đầy đủ: GET, POST, PUT, PATCH, DELETE
8
+ - ✅ URL-encoded form: `postUrlEndCode`, `patchUrlEndCode` (content-type `application/x-www-form-urlencoded`)
9
+ - ✅ File upload với progress tracking qua XHR native (`sendWithFile`)
10
+ - ✅ Response normalization tự động — hỗ trợ nhiều backend format
11
+ - ✅ Pagination tự động từ nhiều format (paging, Spring pagination, cursor-based)
12
+ - ✅ Error handling: 401 → auto redirect, phân biệt 4xx vs 5xx
13
+ - ✅ Caching với IndexedDB (`cacheIndexDB`) — phân biệt theo user
14
+ - ✅ Page zero conversion (`isStartZeroPage`) — UI 1-based ↔ API 0-based
15
+
16
+ ## Cài đặt
17
+
18
+ ```bash
19
+ npm install @libs-ui/services-base-request-abstract
20
+ ```
21
+
22
+ ## Import
23
+
24
+ ```typescript
25
+ import { LibsUiBaseRequestAbstractService } from '@libs-ui/services-base-request-abstract';
26
+ ```
27
+
28
+ ## Cách sử dụng
29
+
30
+ ### Bước 1: Extend và implement 3 abstract methods bắt buộc
31
+
32
+ ```typescript
33
+ import { Injectable } from '@angular/core';
34
+ import { HttpHeaders, HttpParams } from '@angular/common/http';
35
+ import { Router } from '@angular/router';
36
+ import { LibsUiBaseRequestAbstractService } from '@libs-ui/services-base-request-abstract';
37
+ import { UtilsHttpParamsRequest } from '@libs-ui/utils';
38
+
39
+ @Injectable({ providedIn: 'root' })
40
+ export class ApiService extends LibsUiBaseRequestAbstractService {
41
+ protected override baseUrl = 'https://api.example.com';
42
+
43
+ constructor(private router: Router) {
44
+ super();
45
+ this.keyCacheUniqueByIdUserLogin = localStorage.getItem('userId') || '';
46
+ }
47
+
48
+ protected getOptions<T>(params: UtilsHttpParamsRequest<T>, contentType?: string) {
49
+ const token = localStorage.getItem('accessToken');
50
+ return {
51
+ headers: new HttpHeaders({
52
+ 'Content-Type': contentType || 'application/json',
53
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
54
+ }),
55
+ params,
56
+ };
57
+ }
58
+
59
+ protected redirectToLogin(): void {
60
+ this.router.navigate(['/login']);
61
+ }
62
+
63
+ protected replaceURLByPattern<T>(url: string, params: UtilsHttpParamsRequest<T>) {
64
+ let resultUrl = url;
65
+ const pattern = /:([\w]+)/g;
66
+ let match;
67
+ while ((match = pattern.exec(url)) !== null) {
68
+ const key = match[1];
69
+ if (params.has(key)) {
70
+ resultUrl = resultUrl.replace(`:${key}`, params.get(key)!);
71
+ params = params.delete(key);
72
+ }
73
+ }
74
+ return { url: resultUrl, params };
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Bước 2: Tạo feature service kế thừa ApiService
80
+
81
+ ```typescript
82
+ @Injectable({ providedIn: 'root' })
83
+ export class UserService extends ApiService {
84
+ getUsers(params?: { page?: number; size?: number }) {
85
+ return this.get<User[]>('/users', new UtilsHttpParamsRequest(undefined, params));
86
+ }
87
+
88
+ getUserById(id: string) {
89
+ return this.get<User>('/users/:id', new UtilsHttpParamsRequest(undefined, { id }));
90
+ }
91
+
92
+ createUser(body: CreateUserDto) {
93
+ return this.post<User>('/users', body);
94
+ }
95
+
96
+ updateUser(id: string, body: UpdateUserDto) {
97
+ return this.put<User>('/users/:id', body, new UtilsHttpParamsRequest(undefined, { id }));
98
+ }
99
+
100
+ deleteUser(id: string) {
101
+ return this.delete<void>('/users/:id', new UtilsHttpParamsRequest(undefined, { id }));
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### File Upload với Progress Tracking
107
+
108
+ ```typescript
109
+ uploadAvatar(userId: string, file: File, onProgress?: (percent: number) => void) {
110
+ return this.sendWithFile<{ url: string }>(
111
+ '/users/:userId/avatar',
112
+ new UtilsHttpParamsRequest(undefined, { userId }),
113
+ {
114
+ method: 'POST',
115
+ bodyData: { file },
116
+ keepFileOfBody: true,
117
+ processUpload: onProgress ? ({ percent }) => onProgress(percent) : undefined,
118
+ }
119
+ );
120
+ }
121
+ ```
122
+
123
+ ### Caching với IndexedDB
124
+
125
+ ```typescript
126
+ getUsersCached(params?: any) {
127
+ const observable = this.get<User[]>('/users', new UtilsHttpParamsRequest(undefined, params));
128
+ return this.cacheIndexDB(observable, 'users-list', [params], 5 * 60 * 1000);
129
+ }
130
+
131
+ // Xóa cache sau mutation
132
+ async createUser(body: CreateUserDto) {
133
+ const result = await lastValueFrom(this.post<User>('/users', body));
134
+ await this.deleteCacheKeyStartWidth('users-list');
135
+ return result;
136
+ }
137
+ ```
138
+
139
+ ## API
140
+
141
+ ### Abstract Methods (bắt buộc implement)
142
+
143
+ | Method | Returns | Mô tả |
144
+ | ----------------------------------------- | --------------------- | ------------------------------------------------ |
145
+ | `getOptions<T>(httpParams, contentType?)` | `{ headers, params }` | Inject auth token, Content-Type vào mỗi request |
146
+ | `redirectToLogin()` | `void` | Được gọi khi nhận 401 Unauthorized |
147
+ | `replaceURLByPattern<T>(url, params)` | `{ url, params }` | Thay thế URL dynamic segments (`:id`, `:userId`) |
148
+
149
+ ### Public Methods
150
+
151
+ | Method | Returns | Mô tả |
152
+ | --------------------------------------------------- | ------------------------------ | ------------------------------------ |
153
+ | `get<T, P>(path, params?)` | `Observable<IHttpResponse<T>>` | HTTP GET |
154
+ | `post<T, P, B>(path, body, params?)` | `Observable<IHttpResponse<T>>` | HTTP POST |
155
+ | `postUrlEndCode<T, P, B>(path, body, params?)` | `Observable<IHttpResponse<T>>` | POST URL-encoded form |
156
+ | `put<T, P, B>(path, body, params?)` | `Observable<IHttpResponse<T>>` | HTTP PUT |
157
+ | `patch<T, P>(path, body, params?)` | `Observable<IHttpResponse<T>>` | HTTP PATCH |
158
+ | `patchUrlEndCode<T, P>(path, body, params?)` | `Observable<IHttpResponse<T>>` | PATCH URL-encoded form |
159
+ | `delete<T, P>(path, params?)` | `Observable<IHttpResponse<T>>` | HTTP DELETE |
160
+ | `sendWithFile<T, P, B>(path, params, args)` | `Observable<IHttpResponse<T>>` | Upload file với progress |
161
+ | `cacheIndexDB<T>(obs, key, params, time?, reload?)` | `Observable<IHttpResponse<T>>` | Cache IndexedDB ✅ |
162
+ | `deleteCacheKeyStartWidth(key)` | `Promise<void>` | Xóa cache theo prefix |
163
+ | `cacheResponseData<T>(...)` | `Observable<IHttpResponse<T>>` | **Deprecated** — dùng `cacheIndexDB` |
164
+
165
+ ### Protected Properties (override trong subclass)
166
+
167
+ | Property | Type | Default | Mô tả |
168
+ | ----------------------------- | ---------------------- | ----------- | ------------------------------ |
169
+ | `baseUrl` | `string` | `''` | Base URL của API |
170
+ | `keyCacheUniqueByIdUserLogin` | `string` | `''` | User ID suffix cho cache key |
171
+ | `ignoreRedirect401` | `boolean?` | `undefined` | Tắt auto redirect khi 401 |
172
+ | `isStartZeroPage` | `boolean` | `false` | Convert page 1-based → 0-based |
173
+ | `observeResponse` | `'response' \| 'body'` | `'body'` | Mode nhận HTTP response |
174
+
175
+ ## Types
176
+
177
+ ```typescript
178
+ interface IHttpResponse<T> {
179
+ code: number;
180
+ message?: string;
181
+ data?: T;
182
+ paging?: IPaging;
183
+ feCloneCode?: any;
184
+ statusCodeHttp?: number;
185
+ }
186
+
187
+ interface IPaging {
188
+ page?: number;
189
+ per_page?: number;
190
+ total_items?: number;
191
+ total_pages?: number;
192
+ before?: string;
193
+ after?: string;
194
+ previous?: string;
195
+ next?: string;
196
+ }
197
+
198
+ interface IHttpProcessUpload {
199
+ loaded: number;
200
+ total: number;
201
+ percent: number;
202
+ }
203
+ ```
204
+
205
+ ## Lưu ý quan trọng
206
+
207
+ - **Không inject trực tiếp** — class là abstract, phải extend
208
+ - **3 abstract methods** phải implement: `getOptions`, `redirectToLogin`, `replaceURLByPattern`
209
+ - **`cacheIndexDB` > `cacheResponseData`** — `cacheResponseData` đã deprecated
210
+ - **`keyCacheUniqueByIdUserLogin`** — set user ID để tránh cache conflict giữa các user
211
+ - **`sendWithFile` dùng XHR native** — không phải Angular HttpClient (để có progress events)
212
+ - **Response normalization** hỗ trợ nhiều backend format: REST standard, Spring Boot, cursor-based pagination
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@libs-ui/services-base-request-abstract",
3
- "version": "0.2.355-8",
3
+ "version": "0.2.356-0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=18.0.0",
6
6
  "@angular/core": ">=18.0.0",
7
- "@libs-ui/interfaces-types": "0.2.355-8",
8
- "@libs-ui/utils": "0.2.355-8",
7
+ "@libs-ui/interfaces-types": "0.2.356-0",
8
+ "@libs-ui/utils": "0.2.356-0",
9
9
  "rxjs": "~7.8.0"
10
10
  },
11
11
  "sideEffects": false,