Skip to content

Form Data

@t-req/core provides a simple syntax for form submissions, automatically choosing between multipart/form-data and application/x-www-form-urlencoded.

For simple forms without files:

POST https://api.example.com/login
username = {{user}}
password = {{pass}}

This sends:

Content-Type: application/x-www-form-urlencoded
username=john&password=secret

When files are included, @t-req/core uses multipart:

POST https://api.example.com/profile
name = John Doe
avatar = @./images/photo.jpg

This sends:

Content-Type: multipart/form-data; boundary=...
field = value
field=value
field = value with spaces

Spaces around = are optional. Values are trimmed.

file = @./path/to/file.pdf
file = @./path/to/file.pdf | custom-name.pdf
POST https://api.example.com/contact
name = {{userName}}
email = {{userEmail}}
message = {{userMessage}}
attachment = @./{{attachmentPath}}

@t-req/core determines whether a body should be parsed as form data based on these rules:

  1. All non-empty lines must match the name = value pattern
  2. Single-line body with & is treated as pre-encoded URL query string, not form data
  3. Explicit non-form Content-Type (like application/json or text/plain) bypasses form parsing
# This is parsed as form data
POST https://api.example.com/submit
name = John
email = john@example.com
# This is NOT parsed as form data (single line with &)
POST https://api.example.com/submit
name=John&email=john@example.com
# This is NOT parsed as form data (explicit Content-Type)
POST https://api.example.com/submit
Content-Type: application/json
name = John
email = john@example.com

@t-req/core automatically sets the Content-Type:

ConditionContent-Type
Only text fieldsapplication/x-www-form-urlencoded
Any file fieldsmultipart/form-data

Override the automatic detection if needed:

POST https://api.example.com/data
Content-Type: application/x-www-form-urlencoded
field1 = value1
field2 = value2

For APIs expecting JSON, use a regular body:

POST https://api.example.com/login
Content-Type: application/json
{
"username": "{{user}}",
"password": "{{pass}}"
}

Form values are automatically URL-encoded:

POST https://api.example.com/search
query = hello world & more
special = symbols!@#$%

Becomes: query=hello%20world%20%26%20more&special=symbols%21%40%23%24%25

Some APIs expect array fields:

POST https://api.example.com/settings
tags = javascript
tags = typescript
tags = nodejs

This sends three separate tags fields, which many frameworks interpret as an array.

Empty values are valid:

POST https://api.example.com/form
required_field = some value
optional_field =

Add custom headers alongside form data:

POST https://api.example.com/upload
Authorization: Bearer {{token}}
X-Request-ID: {{$uuid()}}
title = My Document
file = @./document.pdf

To see what’s being sent, use the engine with event logging:

import { createEngine } from '@t-req/core';
import { createFetchTransport } from '@t-req/core/runtime';
const engine = createEngine({
transport: createFetchTransport(fetch),
onEvent: (e) => {
if (e.type === 'request:start') {
console.log('Headers:', e.request.headers);
console.log('Body:', e.request.body);
}
},
});