How can I process multipart HTTP uploads in workflows?
Version 3.1.0 of opscotch adds support for HTTP multipart uploads, letting you receive text/JSON and binary content in the same request. This unlocks use cases like “send me the metadata and the file in one hit,” without forcing you to pick one or chain requests. With saftey in mind - this is disabled by default.
Workflows can now accept two multipart fields in a single HTTP request:
body: string payload, available fromcontext.getBody()stream: binary payload, available fromcontext.getStream()
Heres what the curl example would look like (observe the specific field names and content type declarations):
curl "http://localhost:11000/upload" \
-X POST \
-F 'body={"version": "2.0", "method": "initialize"}' \
-F 'stream=@a-binary-file;type=application/octet-stream'
Constraints to note:
- Use the field names
bodyandstreamwhen sending multipart requests. context.getBody()always returns a string;JSON.parse(...)to get a JSON entity when you expect JSON.context.getStream()returns aByteReaderfor the uploaded file. See the docs: /docs/next/apireference#JavascriptContext-getStream. A deeper dive onByteReaderand streaming is in Byte manipulation in workflows.- If you only send one of the parts, that’s fine—use what you receive. If you send neither, there’s nothing to process.
- The HTTP trigger must set
multiPartUploadByteLimitto enable multipart and cap the upload size. Without it, multipart isn’t accepted for that step.
Enabling multipart on your step
To enable multipart uploads for a step http trigger, you must add the multiPartUploadByteLimit property to define the max size (in bytes):
{
"stepId": "my-http-step",
"trigger": {
"http": {
"server": "myServer",
"method": "POST",
"path": "/upload",
"multiPartUploadByteLimit": 1024
}
}
}
If an upload exceeds the limit, it will be rejected; set the value to what you’re comfortable handling.
Straight text/JSON uploads continue to work with Content-Type: application/json via context.getBody(). Straight binary uploads also work with Content-Type: application/octet-stream via context.getStream()—see How can I upload binary files? for more.
Why this matters
Before 3.1.0, there was no way to receive binary data. When this was added, the next problem was you had to choose: send text/JSON or send binary. That meant bolting together two requests (one for the metadata, one for the file) or stuffing everything into base64. Now you can keep things simple and efficient: one call, two parts, clean separation of concerns.
Typical cases:
- Send configuration plus a binary blob in one request (the opscotch packaging app is a good example of this). See blog about the new packager
- Attach metadata for a log bundle and stream the actual archive as the binary.
- Keep workflows slimmer by avoiding extra parsing or double posts.
How to send multipart uploads
Send both JSON/text and a file in one request by naming the multipart parts body and stream:
curl "http://localhost:11000/upload" \
-X POST \
-H "Accept: application/json" \
-F 'body={"version": "2.0", "method": "initialize"}' \
-F 'stream=@a-binary-file;type=application/octet-stream'
You can use any text for body; just remember it arrives as a string. For other text (YAML, CSV, plain notes), it’s still just a string—parse accordingly.
In your workflow JavaScript processor:
let body = context.getBody(); // string; JSON.parse if needed
let stream = context.getStream(); // ByteReader for the uploaded file
// optional pattern:
// const payload = JSON.parse(body);
// process(stream); // see getStream/ByteReader companion post
If you only care about one part (for example, just the binary), you can ignore the other. Nothing breaks—opscotch hands you what was sent.
Single-part uploads still work
Text/JSON only:
curl "http://localhost:11000/upload" \
-X POST \
-H "Content-Type: application/json" \
--data-binary '{"version": "2.0", "method": "initialize"}'
Binary only (handled via context.getStream()):
curl "http://localhost:11000/upload" \
-X POST \
-H "Accept: application/json" \
-H "Content-Type: application/octet-stream" \
--binary-data '@a-binary-file'
If you’re debating which to use: stick with simple JSON when you only need text; switch to multipart when you need both metadata and bytes; use binary-only when you just need the bytes. For more on streaming and binary handling, see the companion posts on getStream(), How can I upload binary files?, and Byte manipulation in workflows.