Skip to content

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.

Released under the MIT License.