@blueprint-ts/core 3.0.0 → 4.0.0-beta.10
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 +94 -0
- package/README.md +25 -1
- package/docs/.vitepress/config.ts +81 -23
- package/docs/index.md +6 -63
- package/docs/{services/laravel → laravel}/pagination.md +19 -6
- package/docs/{services/laravel → laravel}/requests.md +2 -2
- package/docs/services/pagination/index.md +46 -0
- package/docs/services/pagination/infinite-scroller.md +20 -0
- package/docs/services/pagination/page-aware.md +51 -0
- package/docs/services/pagination/state-pagination.md +77 -0
- package/docs/services/pagination/updating-rows.md +52 -0
- package/docs/services/persistence/index.md +46 -0
- package/docs/services/requests/abort-requests.md +29 -0
- package/docs/services/requests/bulk-requests.md +70 -0
- package/docs/services/requests/concurrency.md +58 -0
- package/docs/services/requests/drivers.md +50 -0
- package/docs/services/requests/error-handling.md +153 -0
- package/docs/services/requests/events.md +31 -0
- package/docs/services/requests/getting-started.md +201 -0
- package/docs/services/requests/headers.md +40 -0
- package/docs/services/requests/loading.md +63 -0
- package/docs/services/requests/request-bodies.md +59 -0
- package/docs/services/requests/responses.md +34 -0
- package/docs/services/support/deferred-promise.md +63 -0
- package/docs/services/support/helpers.md +77 -0
- package/docs/services/support/index.md +6 -0
- package/docs/upgrading/v1-to-v2.md +64 -0
- package/docs/upgrading/v2-to-v3.md +52 -0
- package/docs/upgrading/v3-to-v4.md +214 -0
- package/docs/upgrading.md +0 -0
- package/docs/vue/composables/use-confirm-dialog.md +96 -0
- package/docs/vue/composables/use-global-checkbox.md +73 -0
- package/docs/vue/composables/use-is-empty.md +26 -0
- package/docs/vue/composables/use-is-open-from-var.md +32 -0
- package/docs/vue/composables/use-is-open.md +28 -0
- package/docs/vue/composables/use-model-wrapper.md +29 -0
- package/docs/vue/composables/use-on-open.md +26 -0
- package/docs/vue/forms/arrays.md +102 -0
- package/docs/vue/forms/errors.md +52 -0
- package/docs/vue/forms/index.md +99 -0
- package/docs/vue/forms/payloads.md +99 -0
- package/docs/vue/forms/persistence.md +19 -0
- package/docs/vue/forms/state-and-properties.md +26 -0
- package/docs/vue/forms/utilities.md +27 -0
- package/docs/vue/forms/validation.md +189 -0
- package/docs/vue/requests/loading.md +51 -0
- package/docs/vue/{requests → router}/route-resource-binding.md +33 -27
- package/docs/vue/state.md +27 -11
- package/package.json +12 -13
- package/release-tool.json +22 -3
- package/src/{service/bulkRequests → bulkRequests}/BulkRequestSender.ts +29 -17
- package/src/{service/bulkRequests → bulkRequests}/BulkRequestWrapper.ts +5 -5
- package/src/laravel/pagination/dataDrivers/RequestDriver.ts +30 -0
- package/src/laravel/pagination/index.ts +6 -0
- package/src/pagination/BasePaginator.ts +94 -0
- package/src/{service/pagination → pagination}/InfiniteScroller.ts +1 -0
- package/src/{service/pagination → pagination}/PageAwarePaginator.ts +34 -26
- package/src/{service/pagination → pagination}/StatePaginator.ts +2 -8
- package/src/{service/pagination → pagination}/index.ts +1 -3
- package/src/{service/requests → requests}/BaseRequest.ts +89 -4
- package/src/requests/ErrorHandler.ts +144 -0
- package/src/requests/RequestConcurrencyMode.enum.ts +6 -0
- package/src/requests/RequestErrorRouter.ts +89 -0
- package/src/{service/requests → requests}/bodies/FormDataBody.ts +10 -6
- package/src/{service/requests → requests}/contracts/BaseRequestContract.ts +3 -0
- package/src/requests/exceptions/BadGatewayException.ts +3 -0
- package/src/requests/exceptions/BadRequestException.ts +3 -0
- package/src/requests/exceptions/ConflictException.ts +3 -0
- package/src/requests/exceptions/ForbiddenException.ts +3 -0
- package/src/requests/exceptions/GatewayTimeoutException.ts +3 -0
- package/src/requests/exceptions/GoneException.ts +3 -0
- package/src/requests/exceptions/InvalidJsonException.ts +15 -0
- package/src/requests/exceptions/LockedException.ts +3 -0
- package/src/requests/exceptions/MethodNotAllowedException.ts +3 -0
- package/src/requests/exceptions/NotImplementedException.ts +3 -0
- package/src/requests/exceptions/PayloadTooLargeException.ts +3 -0
- package/src/requests/exceptions/PreconditionFailedException.ts +3 -0
- package/src/requests/exceptions/RequestTimeoutException.ts +3 -0
- package/src/requests/exceptions/ServiceUnavailableException.ts +3 -0
- package/src/requests/exceptions/StaleResponseException.ts +13 -0
- package/src/requests/exceptions/TooManyRequestsException.ts +3 -0
- package/src/requests/exceptions/UnsupportedMediaTypeException.ts +3 -0
- package/src/requests/exceptions/index.ts +51 -0
- package/src/requests/factories/FormDataFactory.ts +17 -0
- package/src/{service/requests → requests}/index.ts +9 -3
- package/src/requests/types/RequestConcurrencyOptions.ts +6 -0
- package/src/{service/support → support}/DeferredPromise.ts +1 -1
- package/src/support/index.ts +4 -0
- package/src/vue/composables/useConfirmDialog.ts +5 -1
- package/src/vue/composables/useModelWrapper.ts +3 -0
- package/src/vue/forms/BaseForm.ts +512 -399
- package/src/vue/forms/PropertyAwareArray.ts +6 -2
- package/src/vue/forms/index.ts +4 -4
- package/src/vue/forms/validation/index.ts +5 -2
- package/src/vue/forms/validation/rules/ConfirmedRule.ts +3 -3
- package/src/vue/forms/validation/rules/EmailRule.ts +23 -0
- package/src/vue/forms/validation/rules/JsonRule.ts +28 -0
- package/src/vue/forms/validation/types/BidirectionalRule.ts +2 -2
- package/src/vue/forms/validation/types/ValidationRules.ts +15 -0
- package/src/vue/index.ts +3 -3
- package/src/vue/requests/factories/VueRequestLoaderFactory.ts +3 -2
- package/src/vue/requests/loaders/VueRequestBatchLoader.ts +6 -1
- package/src/vue/requests/loaders/VueRequestLoader.ts +1 -1
- package/src/vue/router/routeResourceBinding/types.ts +3 -3
- package/src/vue/state/State.ts +38 -50
- package/tests/service/helpers/mergeDeep.test.ts +1 -1
- package/tests/service/laravel/pagination/dataDrivers/RequestDriver.test.ts +3 -3
- package/tests/service/laravel/requests/JsonBaseRequest.test.ts +4 -4
- package/tests/service/laravel/requests/PaginationJsonBaseRequest.test.ts +3 -3
- package/tests/service/laravel/requests/responses/JsonResponse.test.ts +2 -2
- package/tests/service/laravel/requests/responses/PaginationResponse.test.ts +2 -2
- package/tests/service/pagination/dtos/PaginationDataDto.test.ts +1 -1
- package/tests/service/pagination/factories/VuePaginationDriverFactory.test.ts +2 -2
- package/tests/service/pagination/frontendDrivers/VuePaginationDriver.test.ts +1 -1
- package/tests/service/requests/ErrorHandler.test.ts +61 -58
- package/tests/service/requests/FormDataBody.test.ts +1 -1
- package/tests/vue/forms/BaseForm.behavior.test.ts +98 -0
- package/docs/.vitepress/theme/Layout.vue +0 -14
- package/docs/.vitepress/theme/components/VersionSelector.vue +0 -64
- package/docs/.vitepress/theme/index.js +0 -13
- package/docs/services/requests/index.md +0 -74
- package/docs/vue/forms.md +0 -477
- package/examples/files/7z2404-x64.exe +0 -0
- package/examples/index.html +0 -14
- package/examples/js/app.js +0 -8
- package/examples/js/router.js +0 -22
- package/examples/js/view/App.vue +0 -49
- package/examples/js/view/layout/DemoPage.vue +0 -28
- package/examples/js/view/pagination/Pagination.vue +0 -28
- package/examples/js/view/pagination/components/errorPagination/ErrorPagination.vue +0 -71
- package/examples/js/view/pagination/components/errorPagination/GetProductsRequest.ts +0 -54
- package/examples/js/view/pagination/components/infiniteScrolling/GetProductsRequest.ts +0 -50
- package/examples/js/view/pagination/components/infiniteScrolling/InfiniteScrolling.vue +0 -57
- package/examples/js/view/pagination/components/tablePagination/GetProductsRequest.ts +0 -50
- package/examples/js/view/pagination/components/tablePagination/TablePagination.vue +0 -63
- package/examples/js/view/requests/Requests.vue +0 -34
- package/examples/js/view/requests/components/abortableRequest/AbortableRequest.vue +0 -36
- package/examples/js/view/requests/components/abortableRequest/GetProductsRequest.ts +0 -25
- package/examples/js/view/requests/components/fileDownloadRequest/DownloadFileRequest.ts +0 -15
- package/examples/js/view/requests/components/fileDownloadRequest/FileDownloadRequest.vue +0 -44
- package/examples/js/view/requests/components/getRequestWithDynamicParams/GetProductsRequest.ts +0 -34
- package/examples/js/view/requests/components/getRequestWithDynamicParams/GetRequestWithDynamicParams.vue +0 -59
- package/examples/js/view/requests/components/serverErrorRequest/ServerErrorRequest.ts +0 -21
- package/examples/js/view/requests/components/serverErrorRequest/ServerErrorRequest.vue +0 -53
- package/src/service/laravel/pagination/contracts/PaginationParamsContract.ts +0 -4
- package/src/service/laravel/pagination/dataDrivers/RequestDriver.ts +0 -32
- package/src/service/laravel/pagination/index.ts +0 -7
- package/src/service/pagination/BasePaginator.ts +0 -36
- package/src/service/pagination/Paginator.ts +0 -11
- package/src/service/requests/ErrorHandler.ts +0 -64
- package/src/service/requests/exceptions/index.ts +0 -19
- package/src/service/requests/factories/FormDataFactory.ts +0 -9
- package/src/service/support/index.ts +0 -3
- /package/src/{service/bulkRequests → bulkRequests}/BulkRequestEvent.enum.ts +0 -0
- /package/src/{service/bulkRequests → bulkRequests}/index.ts +0 -0
- /package/src/{service/laravel → laravel}/pagination/contracts/PaginationResponseBodyContract.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/JsonBaseRequest.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/PaginationJsonBaseRequest.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/index.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/responses/JsonResponse.ts +0 -0
- /package/src/{service/laravel → laravel}/requests/responses/PaginationResponse.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/BaseViewDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/BaseViewDriverFactoryContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginateableRequestContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginationDataDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginationResponseContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/PaginatorLoadDataOptions.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/StatePaginationDataDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/ViewDriverContract.ts +0 -0
- /package/src/{service/pagination → pagination}/contracts/ViewDriverFactoryContract.ts +0 -0
- /package/src/{service/pagination → pagination}/dataDrivers/ArrayDriver.ts +0 -0
- /package/src/{service/pagination → pagination}/dtos/PaginationDataDto.ts +0 -0
- /package/src/{service/pagination → pagination}/dtos/StatePaginationDataDto.ts +0 -0
- /package/src/{service/pagination → pagination}/factories/VueBaseViewDriverFactory.ts +0 -0
- /package/src/{service/pagination → pagination}/factories/VuePaginationDriverFactory.ts +0 -0
- /package/src/{service/pagination → pagination}/frontendDrivers/VueBaseViewDriver.ts +0 -0
- /package/src/{service/pagination → pagination}/frontendDrivers/VuePaginationDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/LocalStorageDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/NonPersistentDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/SessionStorageDriver.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/index.ts +0 -0
- /package/src/{service/persistenceDrivers → persistenceDrivers}/types/PersistenceDriver.ts +0 -0
- /package/src/{service/requests → requests}/RequestEvents.enum.ts +0 -0
- /package/src/{service/requests → requests}/RequestMethod.enum.ts +0 -0
- /package/src/{service/requests → requests}/bodies/JsonBody.ts +0 -0
- /package/src/{service/requests → requests}/contracts/AbortableRequestContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/BodyContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/BodyFactoryContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/DriverConfigContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/HeadersContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/RequestDriverContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/RequestLoaderContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/RequestLoaderFactoryContract.ts +0 -0
- /package/src/{service/requests → requests}/contracts/ResponseContract.ts +0 -0
- /package/src/{service/requests → requests}/drivers/contracts/ResponseHandlerContract.ts +0 -0
- /package/src/{service/requests → requests}/drivers/fetch/FetchDriver.ts +0 -0
- /package/src/{service/requests → requests}/drivers/fetch/FetchResponse.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/NoResponseReceivedException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/NotFoundException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/PageExpiredException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ResponseBodyException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ResponseException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ServerErrorException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/UnauthorizedException.ts +0 -0
- /package/src/{service/requests → requests}/exceptions/ValidationException.ts +0 -0
- /package/src/{service/requests → requests}/factories/JsonBodyFactory.ts +0 -0
- /package/src/{service/requests → requests}/responses/BaseResponse.ts +0 -0
- /package/src/{service/requests → requests}/responses/BlobResponse.ts +0 -0
- /package/src/{service/requests → requests}/responses/JsonResponse.ts +0 -0
- /package/src/{service/requests → requests}/responses/PlainTextResponse.ts +0 -0
- /package/src/{helpers.ts → support/helpers.ts} +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Persistence
|
|
2
|
+
|
|
3
|
+
This service provides simple persistence drivers that implement a common `PersistenceDriver` interface. It is used by `BaseForm`, but can also be used directly.
|
|
4
|
+
|
|
5
|
+
## Available Drivers
|
|
6
|
+
|
|
7
|
+
- `NonPersistentDriver` — no persistence (default for `BaseForm`)
|
|
8
|
+
- `SessionStorageDriver` — uses `sessionStorage`
|
|
9
|
+
- `LocalStorageDriver` — uses `localStorage`
|
|
10
|
+
|
|
11
|
+
All drivers are exported from `@blueprint-ts/core/persistenceDrivers`.
|
|
12
|
+
|
|
13
|
+
## Using A Driver
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { LocalStorageDriver } from '@blueprint-ts/core/persistenceDrivers'
|
|
17
|
+
|
|
18
|
+
const driver = new LocalStorageDriver('optional-suffix')
|
|
19
|
+
|
|
20
|
+
driver.set('my-key', { value: 123 })
|
|
21
|
+
const value = driver.get<{ value: number }>('my-key')
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Implementing A Custom Driver
|
|
25
|
+
|
|
26
|
+
Implement the `PersistenceDriver` interface:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { type PersistenceDriver } from '@blueprint-ts/core/persistenceDrivers'
|
|
30
|
+
|
|
31
|
+
export class MemoryDriver implements PersistenceDriver {
|
|
32
|
+
private store = new Map<string, unknown>()
|
|
33
|
+
|
|
34
|
+
get<T>(key: string): T | null {
|
|
35
|
+
return (this.store.get(key) as T) ?? null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set<T>(key: string, state: T): void {
|
|
39
|
+
this.store.set(key, state)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
remove(key: string): void {
|
|
43
|
+
this.store.delete(key)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Aborting Requests
|
|
2
|
+
|
|
3
|
+
Requests can be aborted by passing an `AbortSignal` to the request.
|
|
4
|
+
|
|
5
|
+
If you want the request library to abort previous in-flight requests automatically, see [Concurrency](/services/requests/concurrency).
|
|
6
|
+
|
|
7
|
+
## Using AbortController
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
const controller = new AbortController()
|
|
11
|
+
|
|
12
|
+
const request = new ExpenseIndexRequest()
|
|
13
|
+
.setAbortSignal(controller.signal)
|
|
14
|
+
|
|
15
|
+
const promise = request.send()
|
|
16
|
+
|
|
17
|
+
// Later, when you want to abort:
|
|
18
|
+
controller.abort()
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Note: If you enable request concurrency with `REPLACE` or `REPLACE_LATEST`, the request will assign its own abort signal and override this one. See [Concurrency](/services/requests/concurrency) for details.
|
|
22
|
+
|
|
23
|
+
## Bulk Requests
|
|
24
|
+
|
|
25
|
+
`BulkRequestSender` internally manages an `AbortController` for its requests. You can abort the entire bulk operation:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
bulkRequestSenderInstance.abort()
|
|
29
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Bulk Requests
|
|
2
|
+
|
|
3
|
+
Bulk requests let you send many requests together with a shared execution mode and retry policy.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
Wrap each request in a `BulkRequestWrapper`, then send them with `BulkRequestSender`:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import {
|
|
11
|
+
BulkRequestExecutionMode,
|
|
12
|
+
BulkRequestSender,
|
|
13
|
+
BulkRequestWrapper,
|
|
14
|
+
BulkRequestEventEnum
|
|
15
|
+
} from '@blueprint-ts/core/bulkRequests'
|
|
16
|
+
|
|
17
|
+
const requests = items.map((item) =>
|
|
18
|
+
new BulkRequestWrapper(new DeleteRequest(item.id))
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const sender = new BulkRequestSender(requests, BulkRequestExecutionMode.PARALLEL, 1)
|
|
22
|
+
|
|
23
|
+
await sender
|
|
24
|
+
.on(BulkRequestEventEnum.REQUEST_SUCCESSFUL, () => {
|
|
25
|
+
// handle success
|
|
26
|
+
})
|
|
27
|
+
.on(BulkRequestEventEnum.REQUEST_FAILED, () => {
|
|
28
|
+
// handle failure
|
|
29
|
+
})
|
|
30
|
+
.send()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Wrapper State
|
|
34
|
+
|
|
35
|
+
`BulkRequestWrapper` tracks per-request state so you can inspect individual results:
|
|
36
|
+
|
|
37
|
+
- `wasSent()`
|
|
38
|
+
- `hasError()`
|
|
39
|
+
- `getError()`
|
|
40
|
+
- `getResponse()`
|
|
41
|
+
|
|
42
|
+
## Sequential vs Parallel
|
|
43
|
+
|
|
44
|
+
- `BulkRequestExecutionMode.PARALLEL` sends all requests at once.
|
|
45
|
+
- `BulkRequestExecutionMode.SEQUENTIAL` sends requests one after another.
|
|
46
|
+
|
|
47
|
+
## Retries
|
|
48
|
+
|
|
49
|
+
Pass a retry count to the sender to retry failed requests:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const sender = new BulkRequestSender(requests, BulkRequestExecutionMode.SEQUENTIAL, 2)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Results
|
|
56
|
+
|
|
57
|
+
`send()` resolves with a summary object:
|
|
58
|
+
|
|
59
|
+
- `getSuccessCount()`
|
|
60
|
+
- `getErrorCount()`
|
|
61
|
+
- `getSuccessfulResponses()`
|
|
62
|
+
- `getFailedResponses()`
|
|
63
|
+
|
|
64
|
+
## Reusing a Sender
|
|
65
|
+
|
|
66
|
+
You can reuse a sender instance with a new set of requests:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
sender.setRequests(nextRequests)
|
|
70
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Request Concurrency
|
|
2
|
+
|
|
3
|
+
Concurrent requests can cause two common problems:
|
|
4
|
+
|
|
5
|
+
1. A slower, older response overwrites newer data ("stale results").
|
|
6
|
+
2. Loading state flickers because earlier requests finish after later ones.
|
|
7
|
+
|
|
8
|
+
To solve this, `BaseRequest` supports an optional concurrency policy that can abort older requests and/or ignore stale responses.
|
|
9
|
+
|
|
10
|
+
## Basic Usage
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { RequestConcurrencyMode } from '@blueprint-ts/core/requests'
|
|
14
|
+
|
|
15
|
+
const request = new ExpenseIndexRequest()
|
|
16
|
+
|
|
17
|
+
request.setConcurrency({
|
|
18
|
+
mode: RequestConcurrencyMode.REPLACE_LATEST,
|
|
19
|
+
key: 'expense-search'
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
request.send()
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Modes
|
|
26
|
+
|
|
27
|
+
- `ALLOW` (default): no aborts and no stale-response filtering.
|
|
28
|
+
- `REPLACE`: aborts any in-flight request with the same key.
|
|
29
|
+
- `LATEST`: ignores stale responses; only the most recent response is applied.
|
|
30
|
+
- `REPLACE_LATEST`: aborts older requests and ignores stale responses.
|
|
31
|
+
|
|
32
|
+
## Abort Signals
|
|
33
|
+
|
|
34
|
+
When using `REPLACE` or `REPLACE_LATEST`, the request creates and assigns its own `AbortController` for the concurrency key. This replaces any previously configured abort signal on that request instance. If you need to preserve a custom abort signal, apply it per request without using replace modes.
|
|
35
|
+
|
|
36
|
+
## Keys
|
|
37
|
+
|
|
38
|
+
The `key` lets you coordinate concurrency across multiple request instances. If you omit it, the request instance ID is used.
|
|
39
|
+
|
|
40
|
+
Use a shared key when multiple instances represent the same logical request stream (for example, a search box that creates new request objects).
|
|
41
|
+
|
|
42
|
+
## Stale Responses
|
|
43
|
+
|
|
44
|
+
When `LATEST` or `REPLACE_LATEST` is used, stale responses raise a `StaleResponseException` so the caller can ignore them safely.
|
|
45
|
+
|
|
46
|
+
If you don't want to handle it explicitly, catch and ignore it:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { StaleResponseException } from '@blueprint-ts/core/requests'
|
|
50
|
+
|
|
51
|
+
request.send().catch((error) => {
|
|
52
|
+
if (error instanceof StaleResponseException) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
throw error
|
|
57
|
+
})
|
|
58
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Drivers
|
|
2
|
+
|
|
3
|
+
Requests are executed by a request driver. The library includes a default fetch-based driver and lets you provide your
|
|
4
|
+
own by implementing `RequestDriverContract`.
|
|
5
|
+
|
|
6
|
+
## Default Fetch Driver
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
import { BaseRequest, FetchDriver } from '@blueprint-ts/core/requests'
|
|
10
|
+
|
|
11
|
+
BaseRequest.setRequestDriver(new FetchDriver())
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The `FetchDriver` supports:
|
|
15
|
+
|
|
16
|
+
- Global headers
|
|
17
|
+
- `corsWithCredentials` configuration
|
|
18
|
+
- `AbortSignal` via request config
|
|
19
|
+
|
|
20
|
+
## Custom Driver
|
|
21
|
+
|
|
22
|
+
To implement your own driver, implement `RequestDriverContract` and return a `ResponseHandlerContract`:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { type RequestDriverContract } from '@blueprint-ts/core/requests'
|
|
26
|
+
import { type ResponseHandlerContract } from '@blueprint-ts/core/requests'
|
|
27
|
+
import { type RequestMethodEnum } from '@blueprint-ts/core/requests'
|
|
28
|
+
import { type HeadersContract } from '@blueprint-ts/core/requests'
|
|
29
|
+
import { type BodyContract } from '@blueprint-ts/core/requests'
|
|
30
|
+
import { type DriverConfigContract } from '@blueprint-ts/core/requests'
|
|
31
|
+
|
|
32
|
+
class CustomDriver implements RequestDriverContract {
|
|
33
|
+
public async send(
|
|
34
|
+
url: URL | string,
|
|
35
|
+
method: RequestMethodEnum,
|
|
36
|
+
headers: HeadersContract,
|
|
37
|
+
body?: BodyContract,
|
|
38
|
+
requestConfig?: DriverConfigContract
|
|
39
|
+
): Promise<ResponseHandlerContract> {
|
|
40
|
+
// Implement your transport here and return a ResponseHandlerContract.
|
|
41
|
+
throw new Error('Not implemented')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Register your driver during app boot:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
BaseRequest.setRequestDriver(new CustomDriver())
|
|
50
|
+
```
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Error Handling
|
|
2
|
+
|
|
3
|
+
When a request fails, `BaseRequest.send()` routes error responses through the request error handler and throws a typed exception.
|
|
4
|
+
|
|
5
|
+
## Flow Overview
|
|
6
|
+
|
|
7
|
+
- The request driver throws a `ResponseException` when it receives a non-OK response.
|
|
8
|
+
- `BaseRequest.send()` catches that `ResponseException` and delegates to `ErrorHandler`.
|
|
9
|
+
- `ErrorHandler` parses the response body with `response.json()` into the request's `ResponseErrorBody` generic.
|
|
10
|
+
- If the parsed body is `undefined`, `NoResponseReceivedException` is thrown.
|
|
11
|
+
- Otherwise, the handler maps the HTTP status to a specific exception and throws it.
|
|
12
|
+
- If the error is not a `ResponseException`, `BaseRequest.send()` rethrows the original error.
|
|
13
|
+
|
|
14
|
+
## Catching Errors
|
|
15
|
+
|
|
16
|
+
When using request concurrency (see [Concurrency](/services/requests/concurrency)), `BaseRequest` can throw a `StaleResponseException` for outdated responses. These should usually be ignored:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { StaleResponseException } from '@blueprint-ts/core/requests'
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await request.send()
|
|
23
|
+
} catch (error: unknown) {
|
|
24
|
+
if (error instanceof StaleResponseException) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
throw error
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- `400` -> `BadRequestException`
|
|
33
|
+
- `401` -> `UnauthorizedException`
|
|
34
|
+
- `403` -> `ForbiddenException`
|
|
35
|
+
- `404` -> `NotFoundException`
|
|
36
|
+
- `405` -> `MethodNotAllowedException`
|
|
37
|
+
- `408` -> `RequestTimeoutException`
|
|
38
|
+
- `409` -> `ConflictException`
|
|
39
|
+
- `410` -> `GoneException`
|
|
40
|
+
- `412` -> `PreconditionFailedException`
|
|
41
|
+
- `413` -> `PayloadTooLargeException`
|
|
42
|
+
- `415` -> `UnsupportedMediaTypeException`
|
|
43
|
+
- `419` -> `PageExpiredException`
|
|
44
|
+
- `422` -> `ValidationException`
|
|
45
|
+
- `423` -> `LockedException`
|
|
46
|
+
- `429` -> `TooManyRequestsException`
|
|
47
|
+
- `500` -> `ServerErrorException`
|
|
48
|
+
- `501` -> `NotImplementedException`
|
|
49
|
+
- `502` -> `BadGatewayException`
|
|
50
|
+
- `503` -> `ServiceUnavailableException`
|
|
51
|
+
- `504` -> `GatewayTimeoutException`
|
|
52
|
+
- Any other status -> `ResponseException`
|
|
53
|
+
|
|
54
|
+
All mapped exceptions extend `ResponseBodyException`, so they provide both `getResponse()` and `getBody()` accessors. `ResponseException` only exposes `getResponse()`.
|
|
55
|
+
Error handling assumes error responses are JSON; if JSON parsing fails, an `InvalidJsonException` is thrown before status mapping runs.
|
|
56
|
+
|
|
57
|
+
When handling errors, treat the caught error as `unknown` and narrow with `instanceof`:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import {
|
|
61
|
+
ResponseException,
|
|
62
|
+
ValidationException,
|
|
63
|
+
UnauthorizedException
|
|
64
|
+
} from '@blueprint-ts/core/requests/exceptions'
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await request.send()
|
|
68
|
+
} catch (error: unknown) {
|
|
69
|
+
if (error instanceof ValidationException) {
|
|
70
|
+
const response = error.getResponse()
|
|
71
|
+
const body = error.getBody()
|
|
72
|
+
// Handle validation errors using response/body.
|
|
73
|
+
} else if (error instanceof UnauthorizedException) {
|
|
74
|
+
const response = error.getResponse()
|
|
75
|
+
const body = error.getBody()
|
|
76
|
+
// Handle auth errors using response/body.
|
|
77
|
+
} else if (error instanceof ResponseException) {
|
|
78
|
+
const response = error.getResponse()
|
|
79
|
+
// Handle other response errors.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If you prefer to avoid manual `instanceof` checks, use the fluent `RequestErrorRouter`:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { RequestErrorRouter } from '@blueprint-ts/core/requests'
|
|
88
|
+
import {
|
|
89
|
+
ResponseException,
|
|
90
|
+
ValidationException,
|
|
91
|
+
UnauthorizedException
|
|
92
|
+
} from '@blueprint-ts/core/requests/exceptions'
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
await request.send()
|
|
96
|
+
} catch (error: unknown) {
|
|
97
|
+
await new RequestErrorRouter()
|
|
98
|
+
.on(ValidationException, (exception) => {
|
|
99
|
+
const response = exception.getResponse()
|
|
100
|
+
const body = exception.getBody()
|
|
101
|
+
// Handle validation errors using response/body.
|
|
102
|
+
})
|
|
103
|
+
.on(UnauthorizedException, (exception) => {
|
|
104
|
+
const response = exception.getResponse()
|
|
105
|
+
const body = exception.getBody()
|
|
106
|
+
// Handle auth errors using response/body.
|
|
107
|
+
})
|
|
108
|
+
.on(ResponseException, (exception) => {
|
|
109
|
+
const response = exception.getResponse()
|
|
110
|
+
// Handle other response errors.
|
|
111
|
+
})
|
|
112
|
+
.otherwise((exception) => {
|
|
113
|
+
// Handle non-response errors or rethrow.
|
|
114
|
+
throw exception
|
|
115
|
+
})
|
|
116
|
+
.handle(error)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Handlers run in the order they are registered. Register specific exceptions before base types like `ResponseException`.
|
|
121
|
+
`RequestErrorRouter.handle()` returns `true` when a handler ran and `false` when no handler matched, so you can rethrow or fall back if needed.
|
|
122
|
+
|
|
123
|
+
## Global Error Handling
|
|
124
|
+
|
|
125
|
+
You can register a global handler that runs before the normal error mapping:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { ErrorHandler } from '@blueprint-ts/core/requests'
|
|
129
|
+
|
|
130
|
+
ErrorHandler.registerHandler((response) => {
|
|
131
|
+
// Inspect response here.
|
|
132
|
+
// Return false to indicate that normal handling should be skipped.
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Note: the handler only aborts when it explicitly returns `false`. Returning `true`, `undefined`, or nothing continues normal error mapping.
|
|
137
|
+
|
|
138
|
+
Example: redirect to login on `401` responses:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { ErrorHandler } from '@blueprint-ts/core/requests'
|
|
142
|
+
import { type ResponseHandlerContract } from '@blueprint-ts/core/requests'
|
|
143
|
+
|
|
144
|
+
ErrorHandler.registerHandler((response: ResponseHandlerContract) => {
|
|
145
|
+
if (response.getStatusCode() !== 401) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
auth.logout()
|
|
150
|
+
|
|
151
|
+
router.push({ name: 'login' })
|
|
152
|
+
})
|
|
153
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Events
|
|
2
|
+
|
|
3
|
+
Requests can emit lifecycle events via `BaseRequest.on(...)`.
|
|
4
|
+
|
|
5
|
+
## Available Events
|
|
6
|
+
|
|
7
|
+
- `RequestEvents.LOADING`: Emits `true` when a request starts and `false` when it finishes.
|
|
8
|
+
|
|
9
|
+
## Loading Event
|
|
10
|
+
|
|
11
|
+
Use the `RequestEvents.LOADING` event to track request loading state:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { RequestEvents } from '@blueprint-ts/core/requests'
|
|
15
|
+
|
|
16
|
+
const request = new ExpenseIndexRequest()
|
|
17
|
+
|
|
18
|
+
request.on(RequestEvents.LOADING, (isLoading: boolean) => {
|
|
19
|
+
// Handle loading state
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
request.send()
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You can also pass the event payload type explicitly via the generic:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
request.on<boolean>(RequestEvents.LOADING, (isLoading) => {
|
|
29
|
+
// isLoading is typed as boolean
|
|
30
|
+
})
|
|
31
|
+
```
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Each API endpoint is represented as a separate class that extends `BaseRequest`. This class specifies the HTTP Method,
|
|
4
|
+
URL, and the expected request/response types.
|
|
5
|
+
|
|
6
|
+
## Request Handling
|
|
7
|
+
|
|
8
|
+
The library leverages a fetch-based driver to perform HTTP requests. The following sections explain how to initialize
|
|
9
|
+
the request driver and define custom requests.
|
|
10
|
+
|
|
11
|
+
## Initializing the Request Driver
|
|
12
|
+
|
|
13
|
+
Before making any requests, you must initialize the appropriate request driver. This is done during your application's
|
|
14
|
+
boot process by using the static `setRequestDriver` method.
|
|
15
|
+
|
|
16
|
+
### Using the Fetch Driver
|
|
17
|
+
|
|
18
|
+
To set up the fetch driver, import `BaseRequest` and `FetchDriver` from '@blueprint-ts/core/requests' and initialize
|
|
19
|
+
the driver as shown:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { BaseRequest, FetchDriver } from '@blueprint-ts/core/requests'
|
|
23
|
+
|
|
24
|
+
BaseRequest.setRequestDriver(new FetchDriver())
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Enabling Credential Support
|
|
28
|
+
|
|
29
|
+
If your requests need to include credentials (e.g., cookies for cross-origin requests), enable credential support as
|
|
30
|
+
follows:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
BaseRequest.setRequestDriver(new FetchDriver({
|
|
34
|
+
corsWithCredentials: true,
|
|
35
|
+
}))
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Adding Global Headers
|
|
39
|
+
|
|
40
|
+
To include headers such as a CSRF token with every request, define them globally:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
BaseRequest.setRequestDriver(new FetchDriver({
|
|
44
|
+
headers: {
|
|
45
|
+
'X-XSRF-TOKEN': "<token>",
|
|
46
|
+
},
|
|
47
|
+
}))
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Sometimes you want to refetch the header when the request is sent. You may specify a callback for this:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
BaseRequest.setRequestDriver(new FetchDriver({
|
|
54
|
+
headers: {
|
|
55
|
+
'X-XSRF-TOKEN': () => getCookie('XSRF-TOKEN')
|
|
56
|
+
},
|
|
57
|
+
}))
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Specifying a Base URL
|
|
61
|
+
|
|
62
|
+
In case your backend lives on a separate domain, you may specify a default base url, which is prepended to every request url:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
BaseRequest.setDefaultBaseUrl('https://example.com')
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Example: Expense Index Request
|
|
69
|
+
|
|
70
|
+
The following example demonstrates how to define a GET request to the `/api/v1/expenses` endpoint:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { BaseRequest, RequestMethodEnum, JsonResponse } from '@blueprint-ts/core/requests'
|
|
74
|
+
|
|
75
|
+
export interface GenericResponseErrorInterface {
|
|
76
|
+
message: string
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ExpenseIndexRequestParams {
|
|
80
|
+
filter?: {
|
|
81
|
+
search_text?: string
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface ExpenseResource {
|
|
86
|
+
id: string;
|
|
87
|
+
// other data fields
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ExpenseIndexRequestResponseBody {
|
|
91
|
+
data: ExpenseResource[]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class ExpenseIndexRequest extends BaseRequest<
|
|
95
|
+
boolean, // Generic RequestLoaderLoadingType
|
|
96
|
+
GenericResponseErrorInterface, // Generic ResponseErrorBody
|
|
97
|
+
ExpenseIndexRequestResponseBody, // Generic ResponseBodyInterface
|
|
98
|
+
JsonResponse<ExpenseIndexRequestResponseBody>, // Generic ResponseClass
|
|
99
|
+
undefined, // Generic RequestBodyInterface
|
|
100
|
+
ExpenseIndexRequestParams // RequestParamsInterface
|
|
101
|
+
> {
|
|
102
|
+
public method(): RequestMethodEnum {
|
|
103
|
+
return RequestMethodEnum.GET
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public url(): string {
|
|
107
|
+
return '/api/v1/expenses'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Explanation
|
|
113
|
+
|
|
114
|
+
- **HTTP Method**: Uses `GET` to retrieve data from the `/api/v1/expenses` endpoint.
|
|
115
|
+
- **Error Handling**: On failure (4XX/5XX status codes), the response will conform to `GenericResponseErrorInterface`.
|
|
116
|
+
- **Success Response**: A successful response is expected to follow the `ExpenseIndexRequestResponseBody` interface.
|
|
117
|
+
- **Response Format**: The response is of type JSON, as indicated by `JsonResponse`.
|
|
118
|
+
- **Request Body**: Since this is a GET request, the body is `undefined`.
|
|
119
|
+
- **Query Parameters**: Accepts query parameters that match the `ExpenseIndexRequestParams` interface.
|
|
120
|
+
|
|
121
|
+
### Sending the Request
|
|
122
|
+
|
|
123
|
+
Once the request is defined, you can send it using the following code:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const request = new ExpenseIndexRequest()
|
|
127
|
+
|
|
128
|
+
// The response type and body are inferred automatically.
|
|
129
|
+
const response: JsonResponse<ExpenseIndexRequestResponseBody> = await request.send()
|
|
130
|
+
|
|
131
|
+
const body = response.getBody() // Type: ExpenseIndexRequestResponseBody
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Example: Create Expense Request (POST)
|
|
135
|
+
|
|
136
|
+
This example demonstrates a POST request that sends a JSON body by overriding `getRequestBodyFactory()`:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import {
|
|
140
|
+
BaseRequest,
|
|
141
|
+
RequestMethodEnum,
|
|
142
|
+
JsonResponse,
|
|
143
|
+
JsonBodyFactory
|
|
144
|
+
} from '@blueprint-ts/core/requests'
|
|
145
|
+
|
|
146
|
+
export interface CreateExpensePayload {
|
|
147
|
+
title: string
|
|
148
|
+
amount: number
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface CreateExpenseResponseBody {
|
|
152
|
+
id: string
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export class CreateExpenseRequest extends BaseRequest<
|
|
156
|
+
boolean,
|
|
157
|
+
GenericResponseErrorInterface,
|
|
158
|
+
CreateExpenseResponseBody,
|
|
159
|
+
JsonResponse<CreateExpenseResponseBody>,
|
|
160
|
+
CreateExpensePayload
|
|
161
|
+
> {
|
|
162
|
+
public method(): RequestMethodEnum {
|
|
163
|
+
return RequestMethodEnum.POST
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public url(): string {
|
|
167
|
+
return '/api/v1/expenses'
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public getResponse(): JsonResponse<CreateExpenseResponseBody> {
|
|
171
|
+
return new JsonResponse<CreateExpenseResponseBody>()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public override getRequestBodyFactory() {
|
|
175
|
+
return new JsonBodyFactory<CreateExpensePayload>()
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Explanation
|
|
181
|
+
|
|
182
|
+
- **HTTP Method**: Uses `POST` to create a new expense.
|
|
183
|
+
- **Error Handling**: On failure (4XX/5XX status codes), the response will conform to `GenericResponseErrorInterface`.
|
|
184
|
+
- **Success Response**: A successful response is expected to follow the `CreateExpenseResponseBody` interface.
|
|
185
|
+
- **Response Format**: The response is of type JSON, as indicated by `JsonResponse`.
|
|
186
|
+
- **Request Body**: Uses `JsonBodyFactory` to send JSON with `Content-Type: application/json`.
|
|
187
|
+
|
|
188
|
+
### Sending the Request
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
const request = new CreateExpenseRequest()
|
|
192
|
+
|
|
193
|
+
const response = await request.setBody({
|
|
194
|
+
title: 'Office supplies',
|
|
195
|
+
amount: 42
|
|
196
|
+
}).send()
|
|
197
|
+
|
|
198
|
+
const body = response.getBody() // Type: CreateExpenseResponseBody
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Note: If you use Laravel or an API that wraps payloads under a `data` key, consider using `JsonBaseRequest` from the Laravel integration.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Headers
|
|
2
|
+
|
|
3
|
+
Requests assemble headers from multiple sources before sending:
|
|
4
|
+
|
|
5
|
+
1. **Driver defaults** (global headers set on the driver)
|
|
6
|
+
2. **Request headers** returned by `requestHeaders()`
|
|
7
|
+
3. **Body headers** from the request body factory (e.g., `Content-Type`)
|
|
8
|
+
|
|
9
|
+
Later sources override earlier ones. Header values can be strings or callbacks that resolve at send time.
|
|
10
|
+
|
|
11
|
+
## Global Headers (Driver)
|
|
12
|
+
|
|
13
|
+
Set headers once when you configure the driver:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
BaseRequest.setRequestDriver(new FetchDriver({
|
|
17
|
+
headers: {
|
|
18
|
+
'X-XSRF-TOKEN': () => getCookie('XSRF-TOKEN')
|
|
19
|
+
},
|
|
20
|
+
}))
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Per-Request Headers
|
|
24
|
+
|
|
25
|
+
Override `requestHeaders()` on a request to add headers per request:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { type HeadersContract } from '@blueprint-ts/core/requests'
|
|
29
|
+
|
|
30
|
+
public override requestHeaders(): HeadersContract {
|
|
31
|
+
return {
|
|
32
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Body Headers
|
|
38
|
+
|
|
39
|
+
Request body factories can set headers such as `Content-Type`. For example, `JsonBodyFactory` sets
|
|
40
|
+
`Content-Type: application/json`.
|