Add multipart/related support for file uploads with metadata #1241
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Adds RFC 2387 multipart/related support for uploading files with metadata in a single request.
Fixes #1240
Background
Per RFC 2387, multipart/related provides a mechanism for representing compound objects that are aggregates of related MIME body parts. This is commonly used by APIs like Google Drive to upload a file and its metadata in a single HTTP request.
Key RFC 2387 Requirements
Part Ordering: Section 3.2 specifies that "If not present the 'root' is the first body part in the Multipart/Related entity." This implementation preserves the OpenAPI schema property order to ensure the root part (typically JSON metadata) appears first.
Content-Type: Section 3.1 requires that each part have an appropriate Content-Type header. Many APIs reject the generic
application/octet-streamand require the actual MIME type (e.g.,text/csv,image/png).Type Parameter: The multipart/related Content-Type header's
typeparameter must specify the MIME type of the root part (Section 3.2).Changes
Runtime Support (progenitor-client)
MultipartRelatedBodytrait for types that can be serialized as multipart/relatedMultipartPartstruct with dynamiccontent_type: Stringfieldtypeparameter derived from first part's content-typeCode Generation (progenitor-impl)
Option<String>for content_type and are excluded from the body when not providedRelated Improvements
API Example
Before (not possible):
// multipart/related was not supportedAfter:
Optional fields (automatically excluded when not provided):
Generated Code
Struct with content_type field:
MultipartRelatedBody implementation respects schema order and skips optional fields:
Design Decisions
Why require content_type at compile time?
Making content_type a required parameter (not defaulting to
application/octet-stream) prevents silent bugs. APIs like Google Drive rejectapplication/octet-streamwith a 400 error, so forcing users to specify the MIME type makes the API safer.Why preserve schema order?
RFC 2387 Section 3.2 specifies that the first part is the "root" by default. Many APIs expect metadata (JSON) before file content. Alphabetical sorting would reverse this (file < metadata), breaking these APIs.
Why Option for optional content_type?
Optional binary fields in the OpenAPI schema should not require a content-type if the field isn't being used. Typify generates
Vec<u8>with#[serde(default)]for optional binary fields, so we check both content_type presence and non-empty bytes before including the part.Why derive type parameter dynamically?
RFC 2387 Section 3.2 requires the
typeparameter to specify the content-type of the root (first) part. Hardcodingapplication/jsonwould be incorrect for binary-only multipart bodies.Testing
query-param-defaultsvalidates default value handlingBreaking Changes
None - this feature is new in this PR.