Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions docs/en/v0/guide/quickStart.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ next:
## Install dependencies
::: code-group
```bash [npm]
npm install @duplojs/http@0 @duplojs/utils@1
npm install @duplojs/http@0 @duplojs/utils@1 @duplojs/data-parser-tools@0
```
```bash [yarn]
yarn add @duplojs/http@0 @duplojs/utils@1
yarn add @duplojs/http@0 @duplojs/utils@1 @duplojs/data-parser-tools@0
```
```bash [pnpm]
pnpm add @duplojs/http@0 @duplojs/utils@1
pnpm add @duplojs/http@0 @duplojs/utils@1 @duplojs/data-parser-tools@0
```
:::

Expand Down
14 changes: 14 additions & 0 deletions docs/en/v0/guide/server/getData.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,17 @@ The data is then available in the `Floor`, an object that contains the accumulat
```

Data extraction can be done at two levels. The storage key will be the `dataParser` key.

## Receive FormData
```ts twoslash {6,11}
// @version: 0
<!--@include: @/examples/v0/guide/server/getData/formData.ts-->
```

To receive `FormData`, you just need to configure a `bodyController` on your route. This tells the route to prepare for a `FormData` stream during a request. The parameters defined for this `bodyController` are applied while streaming the body, unlike the `dataParser`, which is applied after the body is received.

::: info
Extraction schemas can be as complex as JSON schemas, because the `FormData` serializer used supports deeper nesting than the default `FormData`.

File extraction is done with the file `dataParser` (`SDPE.file()`) from `@duplojs/server-utils`.
:::
31 changes: 31 additions & 0 deletions docs/examples/v0/guide/server/getData/formData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { controlBodyAsFormData, ResponseContract, useRouteBuilder } from "@duplojs/http";
import { SDPE } from "@duplojs/server-utils";
import { asserts, DPE, E, O, Path } from "@duplojs/utils";

useRouteBuilder("POST", "/documents", {
bodyController: controlBodyAsFormData({ maxFileQuantity: 5 }),
})
.extract({
body: {
userId: DPE.coerce.number(),
files: SDPE.file().array().max(3),
},
})
.handler(
ResponseContract.noContent("files.receive"),
async({ files, userId }, { response }) => {
for (const [index, file] of O.entries(files)) {
asserts(
await file.move(
Path.resolveRelative([
"new/path/of/file",
`${userId}-${index}${file.getExtension() ?? ""}`,
]),
),
E.isRight,
);
}

return response("files.receive");
},
);
6 changes: 3 additions & 3 deletions docs/fr/v0/guide/quickStart.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ next:
## Installation des dépendances
::: code-group
```bash [npm]
npm install @duplojs/http@0 @duplojs/utils@1
npm install @duplojs/http@0 @duplojs/utils@1 @duplojs/data-parser-tools@0
```
```bash [yarn]
yarn add @duplojs/http@0 @duplojs/utils@1
yarn add @duplojs/http@0 @duplojs/utils@1 @duplojs/data-parser-tools@0
```
```bash [pnpm]
pnpm add @duplojs/http@0 @duplojs/utils@1
pnpm add @duplojs/http@0 @duplojs/utils@1 @duplojs/data-parser-tools@0
```
:::

Expand Down
14 changes: 14 additions & 0 deletions docs/fr/v0/guide/server/getData.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,17 @@ Les données sont ensuite disponibles dans le `Floor`, qui est un objet qui cont
```

L'extraction de données peut se faire sur deux niveaux. La clé de stockage sera la clé du `dataParser`.

## Recevoir du FormData
```ts twoslash {6,11}
// @version: 0
<!--@include: @/examples/v0/guide/server/getData/formData.ts-->
```

Pour recevoir du `FormData`, il vous suffit de configurer un `bodyController` sur votre route. Cela permet d'indiquer à la route qu'elle doit se préparer à recevoir un flux de `FormData` lors d'une requête. Les paramètres définis pour ce `bodyController` s'appliquent pendant le flux du body, contrairement au `dataParser` qui s'applique après la réception du body.

::: info
Les schémas d'extraction peuvent avoir la même complexité que ceux d'un JSON, car le serializer de `FormData` utilisé permet des niveaux de profondeur supérieurs au `FormData` de base.

L'extraction de fichiers se fait via le `dataParser` file (`SDPE.file()`) provenant de la librairie `@duplojs/server-utils`.
:::
2 changes: 1 addition & 1 deletion docs/libs/v0/client/getBody.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function getBody(response) {
return response.formData();
}
else {
return response.blob();
return Promise.resolve(undefined);
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/libs/v0/client/getBody.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function getBody(response) {
return response.formData();
}
else {
return response.blob();
return Promise.resolve(undefined);
}
}

Expand Down
26 changes: 1 addition & 25 deletions docs/libs/v0/client/hooks.d.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,4 @@
import { type MaybePromise } from "@duplojs/utils";
import { type NotPredictedClientResponse, type ClientResponse } from "./types/clientResponse";
import { type PromiseRequestParams } from "./promiseRequest";
export type RequestHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (requestParams: GenericPromiseRequestParams) => MaybePromise<PromiseRequestParams>;
export type ResponseHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (response: ClientResponse<GenericPromiseRequestParams>) => MaybePromise<ClientResponse<GenericPromiseRequestParams>>;
export type InformationHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (response: ClientResponse<GenericPromiseRequestParams>) => MaybePromise<void>;
export type ResponseTypeHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (response: ClientResponse<GenericPromiseRequestParams>) => MaybePromise<void>;
export type ExpectedResponseHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (response: ClientResponse<GenericPromiseRequestParams>) => MaybePromise<void>;
export type CodeHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (response: ClientResponse<GenericPromiseRequestParams>) => MaybePromise<void>;
export type NotPredictedResponseHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (response: NotPredictedClientResponse<GenericPromiseRequestParams>) => MaybePromise<void>;
export type ErrorHook<GenericPromiseRequestParams extends PromiseRequestParams = PromiseRequestParams> = (error: unknown, requestParams: GenericPromiseRequestParams) => MaybePromise<void>;
export interface Hooks {
request: RequestHook[];
response: ResponseHook[];
information: Record<string, InformationHook[]>;
code: Record<string, CodeHook[]>;
informationalResponseType: ResponseTypeHook[];
successfulResponseType: ResponseTypeHook[];
redirectionResponseType: ResponseTypeHook[];
clientErrorResponseType: ResponseTypeHook[];
serverErrorResponseType: ResponseTypeHook[];
expectedResponse: ExpectedResponseHook[];
notPredictedResponse: NotPredictedResponseHook[];
error: ErrorHook[];
}
import { type CodeHook, type ErrorHook, type InformationHook, type NotPredictedResponseHook, type RequestHook, type ResponseHook, type ResponseTypeHook, type PromiseRequestParams, type NotPredictedClientResponse, type ClientResponse } from "./types";
export declare function launchRequestHook(clientHook: readonly RequestHook[], promiseRequestHook: readonly RequestHook[], requestParams: PromiseRequestParams): Promise<PromiseRequestParams>;
export declare function launchResponseHook(clientHook: readonly ResponseHook[], promiseRequestHook: readonly ResponseHook[], response: ClientResponse): Promise<ClientResponse>;
export declare function launchInformationHook(clientHook: readonly InformationHook[], promiseRequestHook: readonly InformationHook[], response: ClientResponse): Promise<void>;
Expand Down
5 changes: 5 additions & 0 deletions docs/libs/v0/client/httpClient.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ function createHttpClient(clientParams) {
path,
...params,
})),
patch: ((path, params) => self.request({
method: "PATCH",
path,
...params,
})),
delete: ((path, params) => self.request({
method: "DELETE",
path,
Expand Down
55 changes: 30 additions & 25 deletions docs/libs/v0/client/httpClient.d.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { type Kind, type MayBeGetter, type NeverCoalescing, type SimplifyTopLevel } from "@duplojs/utils";
import { type ClientRequestInitParams, type ServerRoute, type ServerRouteToClientRequestParams, type ServerRouteToClientResponse, type ClientRequestParams } from "./types";
import { PromiseRequest, type PromiseRequestParams } from "./promiseRequest";
import { type Hooks, type RequestHook, type ResponseHook, type InformationHook, type CodeHook, type ResponseTypeHook, type ExpectedResponseHook, type ErrorHook, type NotPredictedResponseHook } from "./hooks";
import { type Kind, type MayBeGetter, type SimplifyTopLevel, type IsEqual } from "@duplojs/utils";
import { type ClientRequestInitParams, type ServerRoute, type ServerRouteToClientRequestParams, type ServerRouteToClientResponse, type ClientRequestParams, type ClientResponse, type Hooks, type RequestHook, type ResponseHook, type InformationHook, type CodeHook, type ResponseTypeHook, type ExpectedResponseHook, type NotPredictedResponseHook, type ErrorHook, type GetServerRoutePath } from "./types";
import { PromiseRequest } from "./promiseRequest";
export declare const httpClientKind: import("@duplojs/utils").KindHandler<import("@duplojs/utils").KindDefinition<"@DuplojsHttpClient/http-client", unknown>>;
type MaybeRequestParams<GenericRequestParams extends object> = {} extends GenericRequestParams ? [params?: GenericRequestParams] : [params: GenericRequestParams];
type HttpClientRequestMethod<GenericServerRoute extends ServerRoute, GenericHookParams extends Record<string, unknown>, GenericMethod extends string> = <GenericClientRequestParams extends NeverCoalescing<ServerRouteToClientRequestParams<Extract<GenericServerRoute, {
type HttpClientRequestMethod<GenericServerRoute extends ServerRoute, GenericHookParams extends Record<string, unknown>, GenericMethod extends string> = IsEqual<GenericServerRoute, ServerRoute> extends true ? (path: string, params?: SimplifyTopLevel<Omit<ClientRequestParams<GenericHookParams>, "method" | "path">>) => PromiseRequest<GenericHookParams, ClientResponse<GenericHookParams>> : <GenericPath extends Extract<GenericServerRoute, {
method: GenericMethod;
}>, GenericHookParams>, ClientRequestParams<GenericHookParams>>, GenericPath extends GenericClientRequestParams["path"], GenericClientRequestRest extends SimplifyTopLevel<Omit<NeverCoalescing<Extract<GenericClientRequestParams, {
path: GenericPath;
}>, ClientRequestParams<GenericHookParams>>, "method" | "path">>>(path: GenericPath, ...args: MaybeRequestParams<GenericClientRequestRest>) => PromiseRequest<PromiseRequestParams<GenericHookParams>, ServerRouteToClientResponse<NeverCoalescing<Extract<GenericServerRoute, {
}>["path"], GenericMatchedPath extends GetServerRoutePath<Extract<GenericServerRoute, {
method: GenericMethod;
path: GenericPath;
}>, ServerRoute>, GenericHookParams>>;
}>, GenericPath>>(path: GenericPath, ...args: MaybeRequestParams<SimplifyTopLevel<Omit<ServerRouteToClientRequestParams<Extract<GenericServerRoute, {
method: GenericMethod;
path: GenericMatchedPath | GenericPath;
}>, GenericHookParams>, "method" | "path">>>) => PromiseRequest<GenericHookParams, ServerRouteToClientResponse<Extract<GenericServerRoute, {
method: GenericMethod;
path: GenericMatchedPath;
}>, GenericHookParams>>;
export interface HttpClientConfig {
readonly baseUrl: string;
readonly informationHeaderKey: string;
Expand All @@ -26,25 +28,28 @@ export interface HttpClient<GenericServerRoute extends ServerRoute = ServerRoute
readonly defaultHeaders: Map<string, () => (string | undefined | null)>;
addDefaultHeader(headerName: string, headerValue: MayBeGetter<string | undefined | null>): void;
addDefaultHeaders(headers: Record<string, MayBeGetter<string | undefined | null>>): void;
addRequestHook(hook: RequestHook<PromiseRequestParams<GenericHookParams>>): void;
addResponseHook(hook: ResponseHook<PromiseRequestParams<GenericHookParams>>): void;
addInformationHook(information: string, hook: InformationHook<PromiseRequestParams<GenericHookParams>>): void;
addCodeHook(code: string, hook: CodeHook<PromiseRequestParams<GenericHookParams>>): void;
addInformationalResponseTypeHook(hook: ResponseTypeHook<PromiseRequestParams<GenericHookParams>>): void;
addSuccessfulResponseTypeHook(hook: ResponseTypeHook<PromiseRequestParams<GenericHookParams>>): void;
addRedirectionResponseTypeHook(hook: ResponseTypeHook<PromiseRequestParams<GenericHookParams>>): void;
addClientErrorResponseTypeHook(hook: ResponseTypeHook<PromiseRequestParams<GenericHookParams>>): void;
addServerErrorResponseTypeHook(hook: ResponseTypeHook<PromiseRequestParams<GenericHookParams>>): void;
addExpectedResponseHook(hook: ExpectedResponseHook<PromiseRequestParams<GenericHookParams>>): void;
addNotPredictedResponseHook(hook: NotPredictedResponseHook<PromiseRequestParams<GenericHookParams>>): void;
addErrorHook(hook: ErrorHook<PromiseRequestParams<GenericHookParams>>): void;
request<GenericClientRequestParams extends ServerRouteToClientRequestParams<GenericServerRoute, GenericHookParams>>(params: GenericClientRequestParams): PromiseRequest<PromiseRequestParams<GenericHookParams>, ServerRouteToClientResponse<Extract<GenericServerRoute, {
addRequestHook(hook: RequestHook<GenericHookParams>): void;
addResponseHook(hook: ResponseHook<GenericHookParams>): void;
addInformationHook(information: string, hook: InformationHook<GenericHookParams>): void;
addCodeHook(code: string, hook: CodeHook<GenericHookParams>): void;
addInformationalResponseTypeHook(hook: ResponseTypeHook<GenericHookParams>): void;
addSuccessfulResponseTypeHook(hook: ResponseTypeHook<GenericHookParams>): void;
addRedirectionResponseTypeHook(hook: ResponseTypeHook<GenericHookParams>): void;
addClientErrorResponseTypeHook(hook: ResponseTypeHook<GenericHookParams>): void;
addServerErrorResponseTypeHook(hook: ResponseTypeHook<GenericHookParams>): void;
addExpectedResponseHook(hook: ExpectedResponseHook<GenericHookParams>): void;
addNotPredictedResponseHook(hook: NotPredictedResponseHook<GenericHookParams>): void;
addErrorHook(hook: ErrorHook<GenericHookParams>): void;
request<GenericClientRequestParams extends ServerRouteToClientRequestParams<GenericServerRoute, GenericHookParams>, GenericMatchedPath extends GetServerRoutePath<Extract<GenericServerRoute, {
method: GenericClientRequestParams["method"];
}>, GenericClientRequestParams["path"]>>(params: GenericClientRequestParams): PromiseRequest<GenericHookParams, ServerRouteToClientResponse<Extract<GenericServerRoute, {
method: GenericClientRequestParams["method"];
path: GenericClientRequestParams["path"];
path: GenericMatchedPath;
}>, GenericHookParams>>;
get: HttpClientRequestMethod<GenericServerRoute, GenericHookParams, "GET">;
post: HttpClientRequestMethod<GenericServerRoute, GenericHookParams, "POST">;
put: HttpClientRequestMethod<GenericServerRoute, GenericHookParams, "PUT">;
patch: HttpClientRequestMethod<GenericServerRoute, GenericHookParams, "PATCH">;
delete: HttpClientRequestMethod<GenericServerRoute, GenericHookParams, "DELETE">;
}
export interface CreateHttpClientParams {
Expand All @@ -56,5 +61,5 @@ export interface CreateHttpClientParams {
readonly predictedHeaderKey?: string;
readonly disabledPredictedMode?: boolean;
}
export declare function createHttpClient<GenericServerRoute extends ServerRoute = never, GenericHookParams extends Record<string, unknown> = Record<string, unknown>>(clientParams: CreateHttpClientParams): HttpClient<NeverCoalescing<GenericServerRoute, ServerRoute>, GenericHookParams>;
export declare function createHttpClient<GenericServerRoute extends ServerRoute = ServerRoute, GenericHookParams extends Record<string, unknown> = Record<string, unknown>>(clientParams: CreateHttpClientParams): HttpClient<GenericServerRoute, GenericHookParams>;
export {};
5 changes: 5 additions & 0 deletions docs/libs/v0/client/httpClient.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ function createHttpClient(clientParams) {
path,
...params,
})),
patch: ((path, params) => self.request({
method: "PATCH",
path,
...params,
})),
delete: ((path, params) => self.request({
method: "DELETE",
path,
Expand Down
3 changes: 3 additions & 0 deletions docs/libs/v0/client/promiseRequest.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ class PromiseRequest extends Promise {
headers["content-type"] = "text/plain; charset=utf-8";
body = body.toString();
}
else if (body instanceof utils.TheFormData) {
headers["content-type-options"] = "advanced";
}
else if ((body
&& typeof body === "object"
&& body?.constructor?.name === "Object")
Expand Down
Loading