Skip to content

enable streaming with multiple file types#1278

Closed
drahnr wants to merge 25 commits into
oxidecomputer:mainfrom
drahnr:tetrazyk
Closed

enable streaming with multiple file types#1278
drahnr wants to merge 25 commits into
oxidecomputer:mainfrom
drahnr:tetrazyk

Conversation

@drahnr

@drahnr drahnr commented Jan 5, 2026

Copy link
Copy Markdown
Contributor

Obsoletes #418 #609

Closes #518

CC @JMendyk

@drahnr

drahnr commented Feb 2, 2026

Copy link
Copy Markdown
Contributor Author

Could someone take a quick look and allow the workflow? Thanks!

Copilot AI review requested due to automatic review settings June 30, 2026 08:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds initial multipart/form-data request body support to the Progenitor generator and client runtime, along with new fixtures and golden outputs to validate generated code for multipart request bodies.

Changes:

  • Add multipart/form-data as a recognized body content type and generate request-building code that uses a multipart form builder.
  • Introduce FormPart/BinaryFormPart/TextFormPart (plus Filename and ContentType newtypes) in progenitor-client and a RequestBuilderExt::form_from_parts() helper.
  • Add a sample OpenAPI spec and extensive generator tests/golden outputs covering mixed multipart field types and encodings.

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sample_openapi/example_multipart.json Adds a minimal multipart OpenAPI fixture used by output verification.
progenitor-impl/tests/test_specific.rs Adds multipart-focused generator tests (including edge cases).
progenitor-impl/tests/test_output.rs Adds output verification for the new multipart fixture.
progenitor-impl/tests/output/src/example_multipart_positional.rs New golden output for positional client generation for multipart example.
progenitor-impl/tests/output/src/example_multipart_httpmock.rs New golden output for httpmock helpers for multipart example.
progenitor-impl/tests/output/src/example_multipart_cli.rs New golden output for CLI generation for multipart example.
progenitor-impl/tests/output/src/example_multipart_builder.rs New golden output for builder-style client generation for multipart example.
progenitor-impl/tests/output/src/example_multipart_builder_tagged.rs New golden output for tagged builder-style generation for multipart example.
progenitor-impl/src/method.rs Adds FormData body type + a Form(TypeId) parameter type and emits .form_from_parts(...) for multipart bodies.
progenitor-impl/src/lib.rs Adds generator state for form metadata and generates as_form() impls for multipart form structs.
progenitor-impl/src/httpmock.rs Updates httpmock wrapper generation to account for form parameters.
progenitor-impl/src/cli.rs Updates CLI generation to handle OperationParameterType::Form for body type lookup.
progenitor-client/tests/client_test.rs Adds unit tests for new multipart form part APIs and newtypes.
progenitor-client/src/progenitor_client.rs Implements multipart form part types/newtypes and RequestBuilderExt::form_from_parts().
progenitor-client/Cargo.toml Adds assert_matches as a dev-dependency for new tests.
Cargo.toml Enables reqwest multipart feature; adds assert_matches; enables tokio macros feature.
Cargo.lock Updates lockfile for new dependencies/features.
cargo-progenitor/src/main.rs Updates generated dependency snippet to include reqwest multipart feature.
Comments suppressed due to low confidence (1)

progenitor-impl/src/httpmock.rs:235

  • httpmock wrapper generation treats multipart/form-data bodies the same as JSON bodies (json_body_obj). This will not match actual multipart requests and makes the generated httpmock helpers misleading for operations whose body is multipart/form-data.

For multipart bodies, consider not generating a body matcher by default (or matching only on headers), and let callers add custom matching behavior if they need it.

                    OperationParameterKind::Body(body_content_type) => match typ {
                        OperationParameterType::Type(_) | OperationParameterType::Form(_) => (
                            true,
                            quote! {
                                Self(self.0.json_body_obj(value))
                            },
                        ),

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +425 to +433
if meta.is_binary {
// Binary fields: Option<bytes::Bytes> -> FormPart::Binary
// Use .into() to support custom binary types via with_conversion
Some(quote! {
if let Some(ref val) = self.#ident {
parts.push((#api_name, progenitor_client::FormPart::Binary(
progenitor_client::BinaryFormPart {
data: val.clone().into(),
filename: None,
Comment on lines +447 to +452
if let Some(ref val) = self.#ident {
parts.push((#api_name, progenitor_client::FormPart::Text(
progenitor_client::TextFormPart {
value: serde_json::to_string(val)
.expect("multipart form field serialization should not fail"),
content_type: #json_content_type,
Comment on lines +2178 to +2179
let mut fields = IndexMap::new();
for (name, property) in properties {
Comment on lines +187 to +196
/// Binary form part data with optional filename and content-type.
#[derive(Debug, Clone)]
pub struct BinaryFormPart {
/// The binary data
pub data: Bytes,
/// Optional filename for the part
pub filename: Option<Filename>,
/// Optional content-type override
pub content_type: Option<ContentType>,
}
Comment on lines +806 to +812
#[test]
#[should_panic(expected = "unreachable")]
fn test_multipart_empty_properties_panics() {
let spec = make_multipart_spec("upload_empty", serde_json::json!({}));
let mut generator = make_builder_generator();
let _ = generator.generate_tokens(&spec);
}
@drahnr drahnr closed this Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content multipart/form-data is not supported

2 participants