@rivinia/http 1.0.0 → 1.0.1
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.
- package/CHANGELOG.md +4 -0
- package/README.md +28 -386
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -3,410 +3,52 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@rivinia/http)
|
|
4
4
|
[](https://www.npmjs.com/package/@rivinia/http)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
<img src="https://raw.githubusercontent.com/abdelfattahqandil21-oss/Revinia/http/v1.0.0/assets/rivinia-abstract-mark-light.svg" alt="Rivinia" width="340" />
|
|
8
|
-
</p>
|
|
6
|
+
A typed Angular HTTP client for Observable requests and reactive resources.
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
requests and reactive `httpResource` requests. It leaves URLs, backend
|
|
12
|
-
contracts, and interceptors under app control. Response bodies pass through
|
|
13
|
-
unchanged unless a request explicitly asks to unwrap one.
|
|
14
|
-
|
|
15
|
-
- Package version: **1.0.0**
|
|
16
|
-
- Requires Angular `^22.0.0` and RxJS `^6.5.3 || ^7.4.0`; `tslib` is installed
|
|
17
|
-
as a dependency.
|
|
18
|
-
|
|
19
|
-
## Install and configure
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install @rivinia/http
|
|
23
|
-
ng add @rivinia/http
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
For a standalone app, `ng add` adds `provideHttpClient()` and
|
|
27
|
-
`provideRiviniaHttp()` to the selected project's `src/app/app.config.ts`.
|
|
28
|
-
It has no prompts and does not set a base URL or an envelope policy. It is
|
|
29
|
-
idempotent and only edits an existing app config containing a `providers: []`
|
|
30
|
-
array; if no config is found it warns and skips, so add the providers
|
|
31
|
-
manually. In a multi-project workspace it targets `defaultProject` or the
|
|
32
|
-
first project; use `--project <name>` to select a project.
|
|
33
|
-
|
|
34
|
-
The equivalent minimal standalone setup is:
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
// src/app/app.config.ts
|
|
38
|
-
import { provideHttpClient } from '@angular/common/http';
|
|
39
|
-
import { ApplicationConfig } from '@angular/core';
|
|
40
|
-
import { provideRiviniaHttp } from '@rivinia/http';
|
|
41
|
-
|
|
42
|
-
export const appConfig: ApplicationConfig = {
|
|
43
|
-
providers: [provideHttpClient(), provideRiviniaHttp()],
|
|
44
|
-
};
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Use the same `provideHttpClient` setup to add app-owned interceptors:
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
import { ApplicationConfig } from '@angular/core';
|
|
51
|
-
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
52
|
-
import { provideRiviniaHttp } from '@rivinia/http';
|
|
53
|
-
import { authInterceptor } from './auth.interceptor';
|
|
54
|
-
|
|
55
|
-
export const appConfig: ApplicationConfig = {
|
|
56
|
-
providers: [provideHttpClient(withInterceptors([authInterceptor])), provideRiviniaHttp()],
|
|
57
|
-
};
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Alternatively, pass features through `provideRiviniaHttp`:
|
|
8
|
+
Package version: **1.0.1**
|
|
61
9
|
|
|
62
10
|
```ts
|
|
63
|
-
import { ApplicationConfig } from '@angular/core';
|
|
64
|
-
import { withInterceptors } from '@angular/common/http';
|
|
65
|
-
import { provideRiviniaHttp } from '@rivinia/http';
|
|
66
|
-
import { authInterceptor } from './auth.interceptor';
|
|
67
|
-
|
|
68
|
-
export const appConfig: ApplicationConfig = {
|
|
69
|
-
providers: [provideRiviniaHttp({ httpFeatures: [withInterceptors([authInterceptor])] })],
|
|
70
|
-
};
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Choose one backend setup: when using `httpFeatures`, do not also call
|
|
74
|
-
`provideHttpClient()`; otherwise the HTTP backend and its default XSRF
|
|
75
|
-
interceptor can be registered twice. If the app already configures
|
|
76
|
-
`provideHttpClient(...)`, keep that and call `provideRiviniaHttp()` without
|
|
77
|
-
`httpFeatures`.
|
|
78
|
-
|
|
79
|
-
## URLs and typed service calls
|
|
80
|
-
|
|
81
|
-
The client sends the endpoint string exactly as given. It never prepends a
|
|
82
|
-
base URL or rewrites a path. Compose URLs yourself, for example with
|
|
83
|
-
`joinUrl` and the app's environment:
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
// src/environments/environment.ts
|
|
87
|
-
export const environment = {
|
|
88
|
-
apiUrl: 'https://api.example.com',
|
|
89
|
-
} as const;
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
```ts
|
|
93
|
-
// src/app/trip.service.ts
|
|
94
11
|
import { Service } from '@angular/core';
|
|
95
|
-
import type { HttpResponse } from '@angular/common/http';
|
|
96
|
-
import { Observable } from 'rxjs';
|
|
97
12
|
import { injectRiviniaHttp, joinUrl } from '@rivinia/http';
|
|
98
|
-
import { environment } from '../environments/environment';
|
|
99
|
-
|
|
100
|
-
export interface Trip {
|
|
101
|
-
id: string;
|
|
102
|
-
title: string;
|
|
103
|
-
departureDate: string;
|
|
104
|
-
status: 'planned' | 'booked' | 'cancelled';
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export interface TripDraft {
|
|
108
|
-
title: string;
|
|
109
|
-
departureDate: string;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
interface ApiEnvelope<T> {
|
|
113
|
-
data: T;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
13
|
@Service()
|
|
117
14
|
export class TripApi {
|
|
118
15
|
private readonly http = injectRiviniaHttp();
|
|
119
|
-
private readonly
|
|
120
|
-
|
|
121
|
-
list(): Observable<Trip[]> {
|
|
122
|
-
return this.http.get<Trip[]>(this.tripsUrl, {
|
|
123
|
-
params: { page: 1, search: 'coast' },
|
|
124
|
-
unwrap: true,
|
|
125
|
-
unwrapKey: 'data',
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
get(id: string): Observable<Trip> {
|
|
130
|
-
return this.http.get<Trip>(joinUrl(this.tripsUrl, id), {
|
|
131
|
-
unwrap: true,
|
|
132
|
-
unwrapKey: 'data',
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
create(input: TripDraft): Observable<Trip> {
|
|
137
|
-
return this.http.post<Trip>(this.tripsUrl, input, {
|
|
138
|
-
unwrap: true,
|
|
139
|
-
unwrapKey: 'data',
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
replace(id: string, input: TripDraft): Observable<Trip> {
|
|
144
|
-
return this.http.put<Trip>(joinUrl(this.tripsUrl, id), input, {
|
|
145
|
-
unwrap: true,
|
|
146
|
-
unwrapKey: 'data',
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
updateStatus(id: string, status: Trip['status']): Observable<Trip> {
|
|
151
|
-
return this.http.patch<Trip>(
|
|
152
|
-
joinUrl(this.tripsUrl, id),
|
|
153
|
-
{ status },
|
|
154
|
-
{ unwrap: true, unwrapKey: 'data' },
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
cancel(id: string, reason: string): Observable<void> {
|
|
159
|
-
return this.http.delete<void>(joinUrl(this.tripsUrl, id), {
|
|
160
|
-
body: { reason },
|
|
161
|
-
unwrap: true,
|
|
162
|
-
unwrapKey: 'data',
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
downloadItinerary(id: string): Observable<Blob> {
|
|
167
|
-
return this.http.getBlob(joinUrl(this.tripsUrl, `${id}/itinerary`));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
getOperatorNotes(id: string): Observable<string> {
|
|
171
|
-
return this.http.getText(joinUrl(this.tripsUrl, `${id}/operator-notes`));
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
listWithHeaders(): Observable<HttpResponse<ApiEnvelope<Trip[]>>> {
|
|
175
|
-
return this.http.getResponse<ApiEnvelope<Trip[]>>(this.tripsUrl, {
|
|
176
|
-
params: { page: 1 },
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
createAndReadLocation(input: TripDraft): Observable<HttpResponse<ApiEnvelope<Trip>>> {
|
|
181
|
-
return this.http.postResponse<ApiEnvelope<Trip>>(this.tripsUrl, input);
|
|
182
|
-
}
|
|
16
|
+
private readonly url = joinUrl('/api', 'trips');
|
|
17
|
+
list() { return this.http.get<Trip[]>(this.url); }
|
|
183
18
|
}
|
|
184
19
|
```
|
|
185
20
|
|
|
186
|
-
|
|
187
|
-
methods opt in to extracting that field. `getBlob()` downloads a binary file,
|
|
188
|
-
and `getText()` reads plain text; neither method unwraps or checks JSON
|
|
189
|
-
envelopes. `getResponse()` and `postResponse()` return the complete
|
|
190
|
-
`HttpResponse` so the caller can inspect the status and headers; their body
|
|
191
|
-
stays raw and is not unwrapped.
|
|
21
|
+
## Why @rivinia/http
|
|
192
22
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
| `post` | `create(input)` |
|
|
197
|
-
| `put` | `replace(id, input)` |
|
|
198
|
-
| `patch` | `updateStatus(id, status)` |
|
|
199
|
-
| `delete` | `cancel(id, reason)`; its optional request body is passed through. |
|
|
200
|
-
| `getBlob` | `downloadItinerary(id)` |
|
|
201
|
-
| `getText` | `getOperatorNotes(id)` |
|
|
202
|
-
| `getResponse` | `listWithHeaders()` |
|
|
203
|
-
| `postResponse` | `createAndReadLocation(input)` |
|
|
204
|
-
| `getResource` | Reactive paginated list in `TripListComponent`. |
|
|
23
|
+
- Typed Observable requests and reactive `httpResource` requests share one client.
|
|
24
|
+
- URLs, interceptors, and response contracts remain application-owned.
|
|
25
|
+
- Response bodies pass through unless a request explicitly unwraps an envelope.
|
|
205
26
|
|
|
206
|
-
|
|
207
|
-
// Example use where the API returns pagination metadata in a header.
|
|
208
|
-
this.api.listWithHeaders().subscribe((response) => {
|
|
209
|
-
const total = Number(response.headers.get('X-Total-Count') ?? 0);
|
|
210
|
-
console.log(response.status, total, response.body?.data);
|
|
211
|
-
});
|
|
27
|
+
## Install
|
|
212
28
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
console.log(response.status, location, response.body?.data);
|
|
217
|
-
});
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
`Observable<T>` is the compile-time type of the result; it does not validate
|
|
221
|
-
the server payload. `joinUrl` removes one boundary slash and passes absolute
|
|
222
|
-
`http://` or `https://` endpoints through unchanged. Use `params` for query
|
|
223
|
-
values: `null` and `undefined` entries are omitted, while strings, numbers,
|
|
224
|
-
and booleans are stringified. The standard request options also pass
|
|
225
|
-
`headers`, `HttpContext`, and `withCredentials` through to Angular's
|
|
226
|
-
`HttpClient`. Use `HttpContext` with your own interceptors for app-specific
|
|
227
|
-
controls such as opting out of auth.
|
|
228
|
-
|
|
229
|
-
## Reactive resources
|
|
230
|
-
|
|
231
|
-
`getResource` uses Angular's `httpResource`. The endpoint can be a string, a
|
|
232
|
-
signal, or a reactive function; `undefined` disables the request. URL,
|
|
233
|
-
`params`, `headers`, and `context` can be reactive inputs and trigger a new
|
|
234
|
-
request when their signal values change. Other options are read once when
|
|
235
|
-
the resource is created.
|
|
236
|
-
|
|
237
|
-
```ts
|
|
238
|
-
import { Component, signal } from '@angular/core';
|
|
239
|
-
import { injectRiviniaHttp, joinUrl } from '@rivinia/http';
|
|
240
|
-
import { environment } from '../environments/environment';
|
|
241
|
-
|
|
242
|
-
import type { Trip } from './trip.service';
|
|
243
|
-
|
|
244
|
-
@Component({
|
|
245
|
-
selector: 'app-trip-list',
|
|
246
|
-
templateUrl: './trip-list.component.html',
|
|
247
|
-
})
|
|
248
|
-
export class TripListComponent {
|
|
249
|
-
private readonly http = injectRiviniaHttp();
|
|
250
|
-
readonly page = signal(1);
|
|
251
|
-
readonly trips = this.http.getResource<Trip[]>(joinUrl(environment.apiUrl, 'trips'), {
|
|
252
|
-
params: () => ({ page: this.page() }),
|
|
253
|
-
unwrap: true,
|
|
254
|
-
unwrapKey: 'data',
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
nextPage(): void {
|
|
258
|
-
this.page.update((value) => value + 1);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
```html
|
|
264
|
-
<!-- src/app/trip-list.component.html -->
|
|
265
|
-
@if (trips.isLoading()) {
|
|
266
|
-
<p>Loading trips…</p>
|
|
267
|
-
} @else if (trips.hasValue()) {
|
|
268
|
-
<ul>
|
|
269
|
-
@for (trip of trips.value(); track trip.id) {
|
|
270
|
-
<li>{{ trip.title }} — {{ trip.departureDate }} ({{ trip.status }})</li>
|
|
271
|
-
}
|
|
272
|
-
</ul>
|
|
273
|
-
} @else if (trips.error()) {
|
|
274
|
-
<p role="alert">Could not load trips. Try again.</p>
|
|
275
|
-
}
|
|
276
|
-
<button type="button" (click)="nextPage()">Next page</button>
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
In a real app, share the Trip model through a model module. `parse` is optional;
|
|
280
|
-
when provided it runs after envelope validation and unwrapping, and can perform
|
|
281
|
-
runtime validation (for example with Zod or Valibot). A parse error, HTTP
|
|
282
|
-
error, or library envelope error is exposed through `trips.error()`.
|
|
283
|
-
`defaultValue` supplies a value while idle/loading. `reportProgress` is
|
|
284
|
-
forwarded to the resource request; for progress events on an `Observable`,
|
|
285
|
-
use Angular `HttpClient` directly.
|
|
286
|
-
|
|
287
|
-
## Response envelopes and errors
|
|
288
|
-
|
|
289
|
-
By default, all JSON response bodies are returned raw, even when they contain
|
|
290
|
-
a field named `data`. To extract a payload, opt in on that call and provide a
|
|
291
|
-
key:
|
|
292
|
-
|
|
293
|
-
```ts
|
|
294
|
-
this.http.get<Trip[]>(url); // raw response body
|
|
295
|
-
this.http.get<Trip[]>(url, { unwrap: true, unwrapKey: 'data' });
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
The type contract requires `unwrapKey` when `unwrap: true`, and rejects a key
|
|
299
|
-
when unwrapping is off. Extraction is strict and single-level: the response
|
|
300
|
-
must be a non-null, non-array object with that own property. A missing key,
|
|
301
|
-
primitive/array/null body, or empty key throws `RiviniaHttpUnwrapError`;
|
|
302
|
-
it does not silently return the original body. Present values such as `null`,
|
|
303
|
-
`false`, `0`, and `''` are returned as-is. Nested data and sibling fields are
|
|
304
|
-
not modified. `unwrapAs<T>` performs the same one-level extraction outside a
|
|
305
|
-
request; its generic type is an unchecked cast, not runtime validation.
|
|
306
|
-
|
|
307
|
-
An optional envelope policy checks backend-declared failures before
|
|
308
|
-
unwrapping. The default keys are `isSuccess` and `error`; only an object whose
|
|
309
|
-
`isSuccess` value is exactly `false` is considered failed:
|
|
310
|
-
|
|
311
|
-
```ts
|
|
312
|
-
// Apply to JSON request paths made by this configured client.
|
|
313
|
-
provideRiviniaHttp({ envelope: {} });
|
|
314
|
-
|
|
315
|
-
// Or specify a per-request policy; it replaces the global policy.
|
|
316
|
-
this.http.get<Trip[]>(url, {
|
|
317
|
-
envelope: { successKey: 'ok', errorKey: 'message' },
|
|
318
|
-
});
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
When a failure is detected, `RiviniaHttpEnvelopeError` is sent through the
|
|
322
|
-
Observable error channel or appears as the resource error. It carries the raw
|
|
323
|
-
`body` and failure `code`. Set `throwOnFailure: false` for a passive policy.
|
|
324
|
-
Policy validation runs before unwrapping, including on `getResponse` and
|
|
325
|
-
`postResponse`. Those full-response methods return raw `HttpResponse<T>`
|
|
326
|
-
(status, headers, and unwrapped body is not applied). `getBlob` and `getText`
|
|
327
|
-
also return raw bodies and do not run envelope validation.
|
|
328
|
-
|
|
329
|
-
The generic type does not validate the server response. For untrusted or
|
|
330
|
-
loosely typed APIs, validate the extracted value with `getResource`'s `parse`
|
|
331
|
-
hook, or validate in the Observable pipeline in app code. Do not log
|
|
332
|
-
`RiviniaHttpUnwrapError.body` or `RiviniaHttpEnvelopeError.body` without
|
|
333
|
-
considering that they may contain sensitive data.
|
|
334
|
-
|
|
335
|
-
## Public API
|
|
336
|
-
|
|
337
|
-
| Export | Kind | Purpose |
|
|
338
|
-
| ----------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
339
|
-
| `provideRiviniaHttp(config?)` | provider | Sets `envelope` and optional `httpFeatures`; no global unwrap option. |
|
|
340
|
-
| `RiviniaHttp` | class | `get`, `post`, `put`, `patch`, `delete`, `getBlob`, `getText`, `getResponse`, `postResponse`, and `getResource`. |
|
|
341
|
-
| `injectRiviniaHttp()` | function | Injection-context shorthand for `inject(RiviniaHttp)`. |
|
|
342
|
-
| `joinUrl(base, endpoint)` | utility | Removes one boundary slash when joining; absolute HTTP(S) endpoints pass through. |
|
|
343
|
-
| `unwrapAs(body, key)` | utility | Strict, single-level typed extraction. |
|
|
344
|
-
| `extractKey(body, key)` | utility | Strict extraction without a generic cast. |
|
|
345
|
-
| `RiviniaHttpUnwrapError` | class | Error for invalid or missing unwrap properties. |
|
|
346
|
-
| `RiviniaHttpEnvelopeError` | class | Error for a failed configured response envelope. |
|
|
347
|
-
| `RiviniaHttpConfig` | type | `envelope` and `httpFeatures` provider configuration. |
|
|
348
|
-
| `RiviniaEnvelopePolicy` | type | Success key, error key, and failure policy settings. |
|
|
349
|
-
| `RiviniaRequestOptions` | type | Options for requests that may unwrap. |
|
|
350
|
-
| `RiviniaRawOptions` | type | Options for methods that never unwrap. |
|
|
351
|
-
| `RiviniaDeleteOptions` | type | Delete options including an optional request body. |
|
|
352
|
-
| `RiviniaDeleteRequestOptions` | type | Delete options including the unwrap contract. |
|
|
353
|
-
| `RiviniaRequestBase` | type | Shared transport and envelope options. |
|
|
354
|
-
| `RiviniaResourceOptions` | type | Reactive resource options and unwrap contract. |
|
|
355
|
-
| `RiviniaResourceBase` | type | Shared resource-specific options. |
|
|
356
|
-
| `ReactiveInput` | type | Static value, signal, or reactive function input. |
|
|
357
|
-
| `QueryParamsInput` | type | `HttpParams` or a primitive-valued query object. |
|
|
358
|
-
| `RiviniaUnwrapOn` | type | Required key form for `{ unwrap: true }`. |
|
|
359
|
-
| `RiviniaUnwrapOff` | type | Form where an unwrap key is disallowed. |
|
|
360
|
-
|
|
361
|
-
## Testing
|
|
362
|
-
|
|
363
|
-
Use Angular's HTTP testing providers. The testing provider follows
|
|
364
|
-
`provideHttpClient()` so the test backend replaces the real backend:
|
|
365
|
-
|
|
366
|
-
```ts
|
|
367
|
-
import { provideHttpClient } from '@angular/common/http';
|
|
368
|
-
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
|
369
|
-
import { TestBed } from '@angular/core/testing';
|
|
370
|
-
import { provideRiviniaHttp, RiviniaHttp } from '@rivinia/http';
|
|
371
|
-
|
|
372
|
-
TestBed.configureTestingModule({
|
|
373
|
-
providers: [provideHttpClient(), provideHttpClientTesting(), provideRiviniaHttp()],
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
const api = TestBed.inject(RiviniaHttp);
|
|
377
|
-
const requests = TestBed.inject(HttpTestingController);
|
|
378
|
-
api
|
|
379
|
-
.get<unknown[]>('https://api.test/trips', {
|
|
380
|
-
unwrap: true,
|
|
381
|
-
unwrapKey: 'data',
|
|
382
|
-
})
|
|
383
|
-
.subscribe();
|
|
384
|
-
requests.expectOne('https://api.test/trips').flush({ data: [] });
|
|
385
|
-
requests.verify();
|
|
29
|
+
```bash
|
|
30
|
+
npm install @rivinia/http
|
|
31
|
+
ng add @rivinia/http
|
|
386
32
|
```
|
|
387
33
|
|
|
388
|
-
##
|
|
389
|
-
|
|
390
|
-
Global `unwrap` and `unwrapKey` settings were removed in 0.5.0. Move the
|
|
391
|
-
unwrap decision and key to each applicable request:
|
|
392
|
-
|
|
393
|
-
```ts
|
|
394
|
-
// Before
|
|
395
|
-
provideRiviniaHttp({ unwrap: true, unwrapKey: 'data' });
|
|
396
|
-
this.http.get<Trip[]>(url);
|
|
397
|
-
|
|
398
|
-
// After
|
|
399
|
-
provideRiviniaHttp();
|
|
400
|
-
this.http.get<Trip[]>(url, { unwrap: true, unwrapKey: 'data' });
|
|
401
|
-
```
|
|
34
|
+
## Quick start
|
|
402
35
|
|
|
403
|
-
|
|
404
|
-
|
|
36
|
+
1. Configure `provideHttpClient()` and `provideRiviniaHttp()`.
|
|
37
|
+
2. Inject `RiviniaHttp` in a service and compose an endpoint URL.
|
|
38
|
+
3. Render the typed response in a feature.
|
|
405
39
|
|
|
406
|
-
##
|
|
40
|
+
## Compatibility
|
|
407
41
|
|
|
408
|
-
|
|
42
|
+
| Angular | RxJS | Node |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `^22.0.0` | `^6.5.3 or ^7.4.0` | `^22.22.3 or ^24.15.0 or >=26.0.0` |
|
|
409
45
|
|
|
410
|
-
##
|
|
46
|
+
## Go further
|
|
411
47
|
|
|
412
|
-
|
|
48
|
+
| Topic | Read |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| URLs and services | [URLs and services](https://github.com/abdelfattahqandil21-oss/Revinia/blob/http/v1.0.1/docs/http/urls-and-services.md) |
|
|
51
|
+
| Reactive resources | [Reactive resources](https://github.com/abdelfattahqandil21-oss/Revinia/blob/http/v1.0.1/docs/http/resources.md) |
|
|
52
|
+
| Response envelopes and errors | [Response envelopes and errors](https://github.com/abdelfattahqandil21-oss/Revinia/blob/http/v1.0.1/docs/http/envelopes-and-errors.md) |
|
|
53
|
+
| API reference | [API reference](https://github.com/abdelfattahqandil21-oss/Revinia/blob/http/v1.0.1/docs/http/api.md) |
|
|
54
|
+
| Testing | [Testing](https://github.com/abdelfattahqandil21-oss/Revinia/blob/http/v1.0.1/docs/http/testing.md) |
|