@blueprint-ts/core 3.0.0 → 4.0.0-beta.2
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 +28 -0
- package/README.md +25 -1
- package/docs/.vitepress/config.ts +80 -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 +19 -0
- package/docs/services/pagination/page-aware.md +46 -0
- package/docs/services/pagination/state-pagination.md +77 -0
- package/docs/services/pagination/updating-rows.md +36 -0
- package/docs/services/persistence/index.md +46 -0
- package/docs/services/requests/abort-requests.md +25 -0
- package/docs/services/requests/bulk-requests.md +70 -0
- package/docs/services/requests/drivers.md +50 -0
- package/docs/services/requests/error-handling.md +137 -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 +171 -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 +45 -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 +9 -10
- 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/{service/pagination → pagination}/BasePaginator.ts +35 -0
- package/src/{service/pagination → pagination}/InfiniteScroller.ts +1 -0
- package/src/{service/pagination → pagination}/PageAwarePaginator.ts +19 -21
- package/src/{service/pagination → pagination}/StatePaginator.ts +2 -8
- package/src/{service/pagination → pagination}/index.ts +1 -1
- package/src/{service/requests → requests}/BaseRequest.ts +2 -2
- package/src/requests/ErrorHandler.ts +144 -0
- package/src/requests/RequestErrorRouter.ts +89 -0
- package/src/{service/requests → requests}/bodies/FormDataBody.ts +10 -6
- 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/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 +2 -2
- 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 +491 -393
- package/src/vue/forms/PropertyAwareArray.ts +2 -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/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}/Paginator.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/BaseRequestContract.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,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,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,137 @@
|
|
|
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
|
+
- `400` -> `BadRequestException`
|
|
17
|
+
- `401` -> `UnauthorizedException`
|
|
18
|
+
- `403` -> `ForbiddenException`
|
|
19
|
+
- `404` -> `NotFoundException`
|
|
20
|
+
- `405` -> `MethodNotAllowedException`
|
|
21
|
+
- `408` -> `RequestTimeoutException`
|
|
22
|
+
- `409` -> `ConflictException`
|
|
23
|
+
- `410` -> `GoneException`
|
|
24
|
+
- `412` -> `PreconditionFailedException`
|
|
25
|
+
- `413` -> `PayloadTooLargeException`
|
|
26
|
+
- `415` -> `UnsupportedMediaTypeException`
|
|
27
|
+
- `419` -> `PageExpiredException`
|
|
28
|
+
- `422` -> `ValidationException`
|
|
29
|
+
- `423` -> `LockedException`
|
|
30
|
+
- `429` -> `TooManyRequestsException`
|
|
31
|
+
- `500` -> `ServerErrorException`
|
|
32
|
+
- `501` -> `NotImplementedException`
|
|
33
|
+
- `502` -> `BadGatewayException`
|
|
34
|
+
- `503` -> `ServiceUnavailableException`
|
|
35
|
+
- `504` -> `GatewayTimeoutException`
|
|
36
|
+
- Any other status -> `ResponseException`
|
|
37
|
+
|
|
38
|
+
All mapped exceptions extend `ResponseBodyException`, so they provide both `getResponse()` and `getBody()` accessors. `ResponseException` only exposes `getResponse()`.
|
|
39
|
+
Error handling assumes error responses are JSON; if JSON parsing fails, an `InvalidJsonException` is thrown before status mapping runs.
|
|
40
|
+
|
|
41
|
+
When handling errors, treat the caught error as `unknown` and narrow with `instanceof`:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import {
|
|
45
|
+
ResponseException,
|
|
46
|
+
ValidationException,
|
|
47
|
+
UnauthorizedException
|
|
48
|
+
} from '@blueprint-ts/core/requests/exceptions'
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await request.send()
|
|
52
|
+
} catch (error: unknown) {
|
|
53
|
+
if (error instanceof ValidationException) {
|
|
54
|
+
const response = error.getResponse()
|
|
55
|
+
const body = error.getBody()
|
|
56
|
+
// Handle validation errors using response/body.
|
|
57
|
+
} else if (error instanceof UnauthorizedException) {
|
|
58
|
+
const response = error.getResponse()
|
|
59
|
+
const body = error.getBody()
|
|
60
|
+
// Handle auth errors using response/body.
|
|
61
|
+
} else if (error instanceof ResponseException) {
|
|
62
|
+
const response = error.getResponse()
|
|
63
|
+
// Handle other response errors.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If you prefer to avoid manual `instanceof` checks, use the fluent `RequestErrorRouter`:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { RequestErrorRouter } from '@blueprint-ts/core/requests'
|
|
72
|
+
import {
|
|
73
|
+
ResponseException,
|
|
74
|
+
ValidationException,
|
|
75
|
+
UnauthorizedException
|
|
76
|
+
} from '@blueprint-ts/core/requests/exceptions'
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await request.send()
|
|
80
|
+
} catch (error: unknown) {
|
|
81
|
+
await new RequestErrorRouter()
|
|
82
|
+
.on(ValidationException, (exception) => {
|
|
83
|
+
const response = exception.getResponse()
|
|
84
|
+
const body = exception.getBody()
|
|
85
|
+
// Handle validation errors using response/body.
|
|
86
|
+
})
|
|
87
|
+
.on(UnauthorizedException, (exception) => {
|
|
88
|
+
const response = exception.getResponse()
|
|
89
|
+
const body = exception.getBody()
|
|
90
|
+
// Handle auth errors using response/body.
|
|
91
|
+
})
|
|
92
|
+
.on(ResponseException, (exception) => {
|
|
93
|
+
const response = exception.getResponse()
|
|
94
|
+
// Handle other response errors.
|
|
95
|
+
})
|
|
96
|
+
.otherwise((exception) => {
|
|
97
|
+
// Handle non-response errors or rethrow.
|
|
98
|
+
throw exception
|
|
99
|
+
})
|
|
100
|
+
.handle(error)
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Handlers run in the order they are registered. Register specific exceptions before base types like `ResponseException`.
|
|
105
|
+
`RequestErrorRouter.handle()` returns `true` when a handler ran and `false` when no handler matched, so you can rethrow or fall back if needed.
|
|
106
|
+
|
|
107
|
+
## Global Error Handling
|
|
108
|
+
|
|
109
|
+
You can register a global handler that runs before the normal error mapping:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { ErrorHandler } from '@blueprint-ts/core/requests'
|
|
113
|
+
|
|
114
|
+
ErrorHandler.registerHandler((response) => {
|
|
115
|
+
// Inspect response here.
|
|
116
|
+
// Return false to indicate that normal handling should be skipped.
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Note: the handler only aborts when it explicitly returns `false`. Returning `true`, `undefined`, or nothing continues normal error mapping.
|
|
121
|
+
|
|
122
|
+
Example: redirect to login on `401` responses:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { ErrorHandler } from '@blueprint-ts/core/requests'
|
|
126
|
+
import { type ResponseHandlerContract } from '@blueprint-ts/core/requests'
|
|
127
|
+
|
|
128
|
+
ErrorHandler.registerHandler((response: ResponseHandlerContract) => {
|
|
129
|
+
if (response.getStatusCode() !== 401) {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
auth.logout()
|
|
134
|
+
|
|
135
|
+
router.push({ name: 'login' })
|
|
136
|
+
})
|
|
137
|
+
```
|
|
@@ -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`.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Loading
|
|
2
|
+
|
|
3
|
+
Requests can expose loading state through a request loader. You register a loader factory once, and each `BaseRequest`
|
|
4
|
+
instance will ask the factory for a loader.
|
|
5
|
+
|
|
6
|
+
Note: For Vue apps, the library provides `VueRequestLoader` and `VueRequestLoaderFactory` in `@blueprint-ts/core/vue/requests`.
|
|
7
|
+
|
|
8
|
+
## Registering a Loader Factory
|
|
9
|
+
|
|
10
|
+
Use `BaseRequest.setRequestLoaderFactory()` to register a factory that implements `RequestLoaderFactoryContract` and
|
|
11
|
+
returns a `RequestLoaderContract`:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import {
|
|
15
|
+
BaseRequest,
|
|
16
|
+
type RequestLoaderContract,
|
|
17
|
+
type RequestLoaderFactoryContract
|
|
18
|
+
} from '@blueprint-ts/core/requests'
|
|
19
|
+
|
|
20
|
+
class BooleanLoader implements RequestLoaderContract<boolean> {
|
|
21
|
+
private loading = false
|
|
22
|
+
|
|
23
|
+
public isLoading(): boolean {
|
|
24
|
+
return this.loading
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public setLoading(value: boolean): void {
|
|
28
|
+
this.loading = value
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class BooleanLoaderFactory implements RequestLoaderFactoryContract<boolean> {
|
|
33
|
+
public make(): RequestLoaderContract<boolean> {
|
|
34
|
+
return new BooleanLoader()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
BaseRequest.setRequestLoaderFactory(new BooleanLoaderFactory())
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Reading Loading State
|
|
42
|
+
|
|
43
|
+
Once a loader factory is registered, every request created from `BaseRequest` can read loading state:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const request = new ExpenseIndexRequest()
|
|
47
|
+
|
|
48
|
+
request.send()
|
|
49
|
+
|
|
50
|
+
const isLoading = request.isLoading()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Override Loader
|
|
54
|
+
|
|
55
|
+
You can override the loader per request with `setRequestLoader`:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const request = new ExpenseIndexRequest()
|
|
59
|
+
|
|
60
|
+
request.setRequestLoader(customLoader)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This lets you create or share a loader before the request exists, which is useful when loading state must be wired up ahead of time.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Request Bodies
|
|
2
|
+
|
|
3
|
+
Request body factories control how outgoing request bodies are serialized and which `Content-Type` header is sent.
|
|
4
|
+
They are separate from response parsing (response classes control `Accept` and how the response body is parsed).
|
|
5
|
+
|
|
6
|
+
## How It Works
|
|
7
|
+
|
|
8
|
+
When you call `send()`, `BaseRequest` uses the request body factory to build a `BodyContract`:
|
|
9
|
+
|
|
10
|
+
- `getRequestBodyFactory()` returns a `BodyFactoryContract`
|
|
11
|
+
- `BodyFactoryContract.make()` returns a `BodyContract`
|
|
12
|
+
- `BodyContract.getHeaders()` provides headers (like `Content-Type`)
|
|
13
|
+
- `BodyContract.getContent()` provides the serialized body
|
|
14
|
+
|
|
15
|
+
If you call `setBody(...)` without providing a body factory, the body is not sent.
|
|
16
|
+
|
|
17
|
+
## JSON Bodies
|
|
18
|
+
|
|
19
|
+
Use `JsonBodyFactory` to send JSON and set `Content-Type: application/json`:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { BaseRequest, JsonBodyFactory, RequestMethodEnum } from '@blueprint-ts/core/requests'
|
|
23
|
+
|
|
24
|
+
class CreateExpenseRequest extends BaseRequest<boolean, GenericResponseErrorInterface, ExpenseResource, JsonResponse<ExpenseResource>, CreateExpensePayload> {
|
|
25
|
+
public method(): RequestMethodEnum {
|
|
26
|
+
return RequestMethodEnum.POST
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public url(): string {
|
|
30
|
+
return '/api/v1/expenses'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public getResponse(): JsonResponse<ExpenseResource> {
|
|
34
|
+
return new JsonResponse<ExpenseResource>()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public override getRequestBodyFactory() {
|
|
38
|
+
return new JsonBodyFactory<CreateExpensePayload>()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If you are using the Laravel integration, `JsonBaseRequest` already configures the JSON body factory for you.
|
|
44
|
+
|
|
45
|
+
## FormData Bodies
|
|
46
|
+
|
|
47
|
+
Use `FormDataFactory` for multipart requests (uploads, mixed fields):
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { FormDataFactory } from '@blueprint-ts/core/requests'
|
|
51
|
+
|
|
52
|
+
public override getRequestBodyFactory() {
|
|
53
|
+
return new FormDataFactory<FormPayload>()
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Custom Body Factories
|
|
58
|
+
|
|
59
|
+
You can implement your own body factory by returning a `BodyContract` with custom headers and serialization logic.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Responses
|
|
2
|
+
|
|
3
|
+
Requests return a response class that controls the `Accept` header and how the body is parsed.
|
|
4
|
+
|
|
5
|
+
## JsonResponse
|
|
6
|
+
|
|
7
|
+
Use `JsonResponse<T>` for JSON APIs. It sets `Accept: application/json` and parses the body with `response.json()`:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { JsonResponse } from '@blueprint-ts/core/requests'
|
|
11
|
+
|
|
12
|
+
// In your request generic parameters:
|
|
13
|
+
// JsonResponse<ExpenseIndexRequestResponseBody>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## PlainTextResponse
|
|
17
|
+
|
|
18
|
+
Use `PlainTextResponse` for endpoints that return plain text. It sets `Accept: text/plain` and parses the body with
|
|
19
|
+
`response.text()`:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { PlainTextResponse } from '@blueprint-ts/core/requests'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## BlobResponse
|
|
26
|
+
|
|
27
|
+
Use `BlobResponse` for binary responses like files. It sets `Accept` to the provided MIME type (default
|
|
28
|
+
`application/octet-stream`) and parses the body with `response.blob()`:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { BlobResponse } from '@blueprint-ts/core/requests'
|
|
32
|
+
|
|
33
|
+
const response = new BlobResponse('application/pdf')
|
|
34
|
+
```
|