I’m trying to upload files to an image hosting service that only accepts multipart/form-data content type. The problem is I’m working in a restricted environment where FormData isn’t supported.
Here’s what I’m trying to achieve:
const uploadData = new FormData();
uploadData.append('image', fileUrl);
uploadData.append('preset_key', IMAGE_UPLOAD_PRESET);
uploadData.append('account_name', IMAGE_SERVICE_ACCOUNT);
console.log(`Starting upload for item ${itemId}`, API_ENDPOINT, uploadData);
const result = await fetch(API_ENDPOINT, {
method: 'POST',
body: uploadData,
});
The API is very strict about the content format and won’t accept anything other than proper multipart form data. I’ve tried several workarounds but nothing seems to work. What’s the best way to manually construct multipart form data for POST requests when FormData is not available?
You’ll need to manually build the multipart boundary and format the data yourself. I’ve hit this same issue before and got it working by constructing the raw multipart string manually. The trick is creating a unique boundary string and getting the headers right for each field. For file uploads, nail the Content-Disposition header and use proper line endings (\r\n). Here’s what worked for me: const boundary = ‘----formdata-’ + Math.random().toString(36); let body = ‘’; // Add text fields body += --${boundary}\r\n; body += Content-Disposition: form-data; name="preset_key"\r\n\r\n; body += ${IMAGE_UPLOAD_PRESET}\r\n; // Add file data body += --${boundary}\r\n; body += Content-Disposition: form-data; name="image"; filename="upload.jpg"\r\n; body += Content-Type: image/jpeg\r\n\r\n; body += fileData + ‘\r\n’; body += --${boundary}--\r\n; fetch(API_ENDPOINT, { method: ‘POST’, headers: { ‘Content-Type’: multipart/form-data; boundary=${boundary} }, body: body }); Get the boundary formatting exactly right - miss the double dashes or mess up line endings and the API will reject your request.
Binary data handling is where most people screw up with manual multipart construction. You can’t just concatenate binary file data as strings like the previous approach suggests - that’ll corrupt your files. You need to work with ArrayBuffers or Uint8Arrays to handle the binary content properly. What works reliably for me is using TextEncoder to convert text fields to bytes, then merging everything into a single Uint8Array. For the file portion, read it as an ArrayBuffer first, then combine all parts using a helper function that merges typed arrays. The key is treating the entire body as binary data instead of mixing strings and binary. Also, some APIs are picky about exact Content-Type detection, so if you’re getting rejections, try sniffing the actual MIME type from file headers rather than assuming jpeg/png. This approach works consistently across different restricted environments where FormData isn’t available.
Had to solve this exact problem with an old embedded system that was super locked down. Manual multipart construction works, but here’s what saved me hours of debugging.
The real gotcha? Many image hosting services validate the exact byte sequence of your multipart data. They’ll reject requests if your boundary markers don’t match perfectly or there’s any encoding mismatch.
I ended up capturing a working request from a browser using dev tools, then reverse engineering the exact format. Export the request as a HAR file or just copy the raw request body from the network tab.
Once you see what the API expects, you can template it. Pay attention to how they handle the filename parameter and whether they expect additional headers like Content-Length for individual parts.
Test with a tiny dummy image first. Don’t waste time debugging with large files when the issue might be basic formatting. I spent way too long thinking it was binary data when it was just a missing semicolon in the Content-Disposition header.
If you’re still stuck, share the exact error response. Most image APIs give pretty specific error messages about what’s wrong with the multipart format.
I’ve dealt with this exact pain in legacy environments. skip fetch and use XMLHttpRequest with setRequestHeader - older systems usually handle manual multipart way better. also worth checking what polyfills your restricted environment has. you might find FormData support hiding somewhere you didn’t expect.