Skip to content

File Uploads

@t-req/core supports file uploads through the @./path syntax in form data.

POST https://api.example.com/upload
file = @./documents/report.pdf

The file path is relative to the .http file location. @t-req/core automatically:

  • Reads the file content
  • Detects the MIME type from the extension
  • Sets Content-Type: multipart/form-data

Override the filename sent to the server:

POST https://api.example.com/upload
document = @./temp/abc123.pdf | quarterly-report.pdf

The server receives the file as quarterly-report.pdf instead of abc123.pdf.

Upload multiple files in one request:

POST https://api.example.com/upload
avatar = @./images/photo.jpg
resume = @./documents/cv.pdf
cover_letter = @./documents/cover.docx

Combine file uploads with text fields:

POST https://api.example.com/documents
title = Quarterly Report
description = Q4 2025 financial summary
category = finance
document = @./reports/q4-2025.pdf

File paths support variable interpolation:

POST https://api.example.com/upload
document = @./{{uploadDir}}/{{filename}}
const client = createClient({
io: createNodeIO(),
variables: {
uploadDir: 'reports/2025',
filename: 'q4-summary.pdf',
},
});

For APIs expecting raw binary data, use the file reference syntax:

PUT https://api.example.com/files/image.png
Content-Type: image/png
< ./images/photo.png

This sends the raw file content as the request body.

For dynamic file handling, prepare the form data yourself:

const client = createClient();
// Build FormData manually
const formData = new FormData();
formData.append('title', 'My Document');
formData.append('file', new Blob([fileContent]), 'document.pdf');
// Use runString with interpolated body
const httpContent = `
POST https://api.example.com/upload
Content-Type: multipart/form-data
`;
// For complex scenarios, you might need to use fetch directly
const response = await fetch('https://api.example.com/upload', {
method: 'POST',
body: formData,
});

@t-req/core infers MIME types from file extensions:

ExtensionMIME Type
.pdfapplication/pdf
.jsonapplication/json
.xmlapplication/xml
.jpg, .jpegimage/jpeg
.pngimage/png
.gifimage/gif
.txttext/plain
.htmltext/html
.csstext/css
.jsapplication/javascript
.zipapplication/zip

For unknown extensions, application/octet-stream is used.

For very large files:

  1. Memory: The entire file is loaded into memory. For huge files, consider streaming APIs.
  2. Timeout: Increase the timeout for slow uploads:
const response = await client.run('./upload.http', {
timeout: 300000, // 5 minutes
});
  1. Progress: @t-req/core doesn’t currently support upload progress events. For progress tracking, use fetch directly with ReadableStream.

Handle file-related errors:

try {
await client.run('./upload.http');
} catch (error) {
if (error.code === 'ENOENT') {
console.error('File not found');
} else if (error.code === 'EACCES') {
console.error('Permission denied');
} else {
throw error;
}
}