Advanced FormData
You can handle deeply nested, complex FormData by using the appropriate bodyController.
ts
import { controlBodyAsFormData, ResponseContract, useRouteBuilder } from "@duplojs/http";
import { SDPE } from "@duplojs/server-utils";
import { A, asyncPipe, DPE, E, Path } from "@duplojs/utils";
useRouteBuilder("POST", "/documents", {
bodyController: controlBodyAsFormData({ maxFileQuantity: 5 }),
})
.extract({
body: {
userId: DPE.coerce.number(),
files: DPE.object({
alt: DPE.string(),
file: SDPE.file().mimeType(["image/png", "image/jpeg"]),
description: DPE.string(),
}).array(),
},
})
.handler(
ResponseContract.noContent("files.receive"),
async({ files, userId }, { response }) => {
const { success, error } = await asyncPipe(
files,
A.map(
async({ file, ...rest }, { index }) => asyncPipe(
file.move(
Path.resolveRelative([
"super/path",
`${userId}-${index}.${file.getExtension() ?? ""}`,
]),
),
E.whenIsRight(
(fileInterface) => E.success({
path: fileInterface.path,
...rest,
}),
),
),
),
(promises) => Promise.all(promises),
A.group(
(element, { output }) => E.isRight(element)
? output("success", element)
: output("error", element),
),
);
return response("files.receive");
},
);Here, the controlBodyAsFormData function defines the maximum number of files allowed in the payload. Data extraction works just like it does for JSON, except that you can also use the server file dataParser (SDPE.file()).
Send FormData from the client
To send complex FormData, you just need to use the client.
ts
import { createHttpClient } from "@duplojs/http/client";
import { type Routes } from "./types";
import { createFormData } from "@duplojs/utils";
const client = createHttpClient<Routes>({
baseUrl: "http://localhost:1506",
});
await client.post(
"/documents",
{
body: createFormData({
userId: 10,
files: [
{
alt: "super",
file: new File([], "superFile.png"),
description: "Super file.",
},
{
alt: "super 2",
file: new File([], "jonDo.jpg"),
description: "Foo bar.",
},
],
}),
},
).iWantInformationOrThrow("files.receive");Use the createFormData function from @duplojs/utils to get a TheFormData, an extended FormData class that supports complex structures. When the client detects that the body is a TheFormData, it automatically adds a custom header to indicate it to the server (content-type-options: advanced). This also keeps it compatible with standard FormData.
