Skip to content

Commit b06332d

Browse files
fix(client): PascalCase request body schema names
Specs that declare components/schemas with snake_case names (e.g. Latitude.sh's `update_api_key` / `virtual_machine_payload`) emitted struct definitions correctly via to_rust_type_name but wired the schema_name through raw on the generated method signature, producing `request: update_api_key` and a borked compile. Route the JSON / FormUrlEncoded request body schema name through to_rust_type_name like the response side already does. Adds a regression test in operation_generation_test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9c01d50 commit b06332d

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

src/client_generator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,9 @@ impl CodeGenerator {
568568
match rb {
569569
RequestBodyContent::Json { schema_name }
570570
| RequestBodyContent::FormUrlEncoded { schema_name } => {
571+
let rust_type_name = self.to_rust_type_name(schema_name);
571572
let request_ident =
572-
syn::Ident::new(schema_name, proc_macro2::Span::call_site());
573+
syn::Ident::new(&rust_type_name, proc_macro2::Span::call_site());
573574
params.push(quote! { request: #request_ident });
574575
}
575576
RequestBodyContent::Multipart => {

tests/operation_generation_test.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,3 +670,60 @@ fn test_generate_text_plain_operation() {
670670
// Verify content-type header
671671
assert!(result_str.contains("text/plain"));
672672
}
673+
674+
#[test]
675+
fn test_request_body_schema_name_pascal_cased() {
676+
// Specs like Latitude.sh declare components/schemas with snake_case
677+
// names (e.g. `update_api_key`). The struct definitions go through
678+
// `to_rust_type_name` and become `UpdateApiKey`, but the request-body
679+
// parameter type used to be wired in raw, producing
680+
// `request: update_api_key` and a borked compile.
681+
let config = create_test_config();
682+
let generator = CodeGenerator::new(config);
683+
684+
let json_op = OperationInfo {
685+
operation_id: "patchApiKey".to_string(),
686+
method: "PATCH".to_string(),
687+
path: "/auth/api_keys/{id}".to_string(),
688+
summary: None,
689+
description: None,
690+
request_body: Some(RequestBodyContent::Json {
691+
schema_name: "update_api_key".to_string(),
692+
}),
693+
response_schemas: BTreeMap::new(),
694+
parameters: vec![],
695+
supports_streaming: false,
696+
stream_parameter: None,
697+
};
698+
699+
let form_op = OperationInfo {
700+
operation_id: "createToken".to_string(),
701+
method: "POST".to_string(),
702+
path: "/oauth/token".to_string(),
703+
summary: None,
704+
description: None,
705+
request_body: Some(RequestBodyContent::FormUrlEncoded {
706+
schema_name: "create_oauth_token".to_string(),
707+
}),
708+
response_schemas: BTreeMap::new(),
709+
parameters: vec![],
710+
supports_streaming: false,
711+
stream_parameter: None,
712+
};
713+
714+
let analysis = create_test_analysis_with_operations(vec![json_op, form_op]);
715+
let result_str = generator.generate_operation_methods(&analysis).to_string();
716+
717+
assert!(
718+
result_str.contains("request : UpdateApiKey"),
719+
"expected PascalCase JSON request body type, got: {result_str}"
720+
);
721+
assert!(
722+
!result_str.contains("request : update_api_key"),
723+
"raw snake_case schema name leaked into JSON method signature: {result_str}"
724+
);
725+
assert!(
726+
result_str.contains("request : CreateOauthToken"),
727+
"expected PascalCase form-urlencoded request body type, got: {result_str}"
728+
);
729+
}

0 commit comments

Comments
 (0)