Skip to content

Commit dce19ce

Browse files
committed
Support XML::Value with the right content header
1 parent e8f0242 commit dce19ce

File tree

2 files changed

+118
-77
lines changed

2 files changed

+118
-77
lines changed

src/rust/client_gen.rs

Lines changed: 94 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ fn match_tag(tag: &Option<Tag>, path_item: &ReferenceOr<PathItem>) -> bool {
268268
fn param_data_to_type(data: &ParameterData, ref_cache: &mut RefCache) -> Result<DataType> {
269269
match &data.format {
270270
ParameterSchemaOrContent::Schema(ref_or_schema) => {
271-
ref_or_schema_type(ref_or_schema, ref_cache)
271+
ref_or_schema_type(ref_or_schema, ref_cache, None)
272272
}
273273
ParameterSchemaOrContent::Content(_) => {
274274
Err(Error::unimplemented("Content parameter is not supported."))
@@ -301,79 +301,95 @@ fn request_body_params(
301301
"Unexpected ref request body: '{reference}'."
302302
))),
303303
ReferenceOr::Item(body) => {
304-
if body.content.len() != 1 {
305-
Err(Error::unimplemented("Content with not exactly 1 option."))
306-
} else {
307-
let (content_type, media_type) = body.content.first().unwrap();
308-
309-
if content_type.starts_with("application/json") {
310-
let schema = match &media_type.schema {
311-
None => Err(Error::unimplemented("JSON content without schema.")),
312-
Some(schema) => Ok(schema),
313-
};
304+
let (content_type, media_type) =
305+
// TODO: It is in standards that a REST API may support multiple content types
306+
// and we shouldn't fail. Handle this to complete the PR
307+
body.content.first().unwrap();
308+
309+
if content_type.starts_with("application/json") {
310+
let schema = match &media_type.schema {
311+
None => Err(Error::unimplemented("JSON content without schema.")),
312+
Some(schema) => Ok(schema),
313+
};
314+
315+
let param = Param {
316+
original_name: "".to_string(),
317+
name: "value".to_string(),
318+
tpe: ref_or_schema_type(schema?, ref_cache, Some(content_type))?,
319+
required: body.required,
320+
kind: ParamKind::Body,
321+
};
322+
323+
Ok(vec![param])
324+
} else if content_type == "application/octet-stream" {
325+
Ok(vec![Param {
326+
original_name: "".to_string(),
327+
name: "value".to_string(),
328+
tpe: DataType::Binary,
329+
required: body.required,
330+
kind: ParamKind::Body,
331+
}])
332+
} else if content_type == "application/x-yaml" {
333+
let schema = match &media_type.schema {
334+
None => Err(Error::unimplemented("YAML content without schema.")),
335+
Some(schema) => Ok(schema),
336+
};
337+
338+
let param = Param {
339+
original_name: "".to_string(),
340+
name: "value".to_string(),
341+
tpe: ref_or_schema_type(schema?, ref_cache, Some(content_type))?,
342+
required: body.required,
343+
kind: ParamKind::Body,
344+
};
345+
346+
Ok(vec![param])
347+
} else if content_type == "multipart/form-data" {
348+
match &media_type.schema {
349+
None => Err(Error::unimplemented("Multipart content without schema.")),
350+
Some(schema) => match schema {
351+
ReferenceOr::Reference { reference } => Err(Error::unimplemented(format!(
352+
"Unexpected ref multipart schema: '{reference}'."
353+
))),
354+
ReferenceOr::Item(schema) => match &schema.schema_kind {
355+
SchemaKind::Type(Type::Object(obj)) => {
356+
fn multipart_param(
357+
name: &str,
358+
required: bool,
359+
schema: &ReferenceOr<Box<Schema>>,
360+
ref_cache: &mut RefCache,
361+
) -> Result<Param> {
362+
Ok(Param {
363+
original_name: name.to_string(),
364+
name: name.to_case(Case::Snake),
365+
tpe: ref_or_box_schema_type(schema, ref_cache)?,
366+
required,
367+
kind: ParamKind::Multipart,
368+
})
369+
}
314370

315-
Ok(vec![Param {
316-
original_name: "".to_string(),
317-
name: "value".to_string(),
318-
tpe: ref_or_schema_type(schema?, ref_cache)?,
319-
required: body.required,
320-
kind: ParamKind::Body,
321-
}])
322-
} else if content_type == "application/octet-stream" {
323-
Ok(vec![Param {
324-
original_name: "".to_string(),
325-
name: "value".to_string(),
326-
tpe: DataType::Binary,
327-
required: body.required,
328-
kind: ParamKind::Body,
329-
}])
330-
} else if content_type == "multipart/form-data" {
331-
match &media_type.schema {
332-
None => Err(Error::unimplemented("Multipart content without schema.")),
333-
Some(schema) => match schema {
334-
ReferenceOr::Reference { reference } => Err(Error::unimplemented(
335-
format!("Unexpected ref multipart schema: '{reference}'."),
371+
obj.properties
372+
.iter()
373+
.map(|(name, schema)| {
374+
multipart_param(
375+
name,
376+
body.required && obj.required.contains(name),
377+
schema,
378+
ref_cache,
379+
)
380+
})
381+
.collect()
382+
}
383+
_ => Err(Error::unimplemented(
384+
"Object schema expected for multipart request body.",
336385
)),
337-
ReferenceOr::Item(schema) => match &schema.schema_kind {
338-
SchemaKind::Type(Type::Object(obj)) => {
339-
fn multipart_param(
340-
name: &str,
341-
required: bool,
342-
schema: &ReferenceOr<Box<Schema>>,
343-
ref_cache: &mut RefCache,
344-
) -> Result<Param> {
345-
Ok(Param {
346-
original_name: name.to_string(),
347-
name: name.to_case(Case::Snake),
348-
tpe: ref_or_box_schema_type(schema, ref_cache)?,
349-
required,
350-
kind: ParamKind::Multipart,
351-
})
352-
}
353-
354-
obj.properties
355-
.iter()
356-
.map(|(name, schema)| {
357-
multipart_param(
358-
name,
359-
body.required && obj.required.contains(name),
360-
schema,
361-
ref_cache,
362-
)
363-
})
364-
.collect()
365-
}
366-
_ => Err(Error::unimplemented(
367-
"Object schema expected for multipart request body.",
368-
)),
369-
},
370386
},
371-
}
372-
} else {
373-
Err(Error::unimplemented(format!(
374-
"Request body content type: '{content_type}'."
375-
)))
387+
},
376388
}
389+
} else {
390+
Err(Error::unimplemented(format!(
391+
"Request body content type: '{content_type}'."
392+
)))
377393
}
378394
}
379395
}
@@ -449,7 +465,7 @@ fn response_type(response: &ReferenceOr<Response>, ref_cache: &mut RefCache) ->
449465
Some(schema) => Ok(schema),
450466
};
451467

452-
Ok(ref_or_schema_type(schema?, ref_cache)?)
468+
Ok(ref_or_schema_type(schema?, ref_cache, Some(content_type))?)
453469
} else if content_type == "application/octet-stream" {
454470
Ok(DataType::Binary)
455471
} else {
@@ -837,7 +853,13 @@ fn render_method_implementation(method: &Method, error_kind: &ErrorKind) -> Rust
837853
r#"request = request.header(reqwest::header::CONTENT_TYPE, "application/octet-stream");"#,
838854
)
839855
+ NewLine
840-
} else {
856+
} else if param.tpe == DataType::Yaml {
857+
line(
858+
r#"request = request.header(reqwest::header::CONTENT_TYPE, "application/x-yaml");"#,
859+
) + NewLine
860+
}
861+
// Not sure why everything else is assumed to be json (previously)
862+
else {
841863
line(unit() + "request = request.json(" + &param.name + ");") + NewLine
842864
}
843865
}

src/rust/types.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub enum DataType {
7373
Array(Box<DataType>),
7474
MapOf(Box<DataType>),
7575
Json,
76+
Yaml
7677
}
7778

7879
pub fn escape_keywords(name: &str) -> String {
@@ -143,6 +144,11 @@ impl DataType {
143144
let res = rust_name("serde_json::value", "Value");
144145
to_ref(res, top_param)
145146
}
147+
148+
DataType::Yaml => {
149+
let res = rust_name("serde_yaml::value", "Value");
150+
to_ref(res, top_param)
151+
}
146152
}
147153
}
148154
}
@@ -159,7 +165,7 @@ pub fn ref_type_name(reference: &str, ref_cache: &mut RefCache) -> Result<DataTy
159165
}))
160166
}
161167

162-
fn schema_type(schema: &Schema, ref_cache: &mut RefCache) -> Result<DataType> {
168+
fn schema_type(schema: &Schema, ref_cache: &mut RefCache, content_type: Option<&str>) -> Result<DataType> {
163169
match &schema.schema_kind {
164170
SchemaKind::Type(tpe) => match tpe {
165171
Type::String(string_type) => {
@@ -213,7 +219,7 @@ fn schema_type(schema: &Schema, ref_cache: &mut RefCache) -> Result<DataType> {
213219
"Object parameter with Any additional_properties is not supported.",
214220
)),
215221
AdditionalProperties::Schema(element_schema) => Ok(DataType::MapOf(
216-
Box::new(ref_or_schema_type(element_schema, ref_cache)?),
222+
Box::new(ref_or_schema_type(element_schema, ref_cache, None)?),
217223
)),
218224
}
219225
} else {
@@ -238,17 +244,30 @@ fn schema_type(schema: &Schema, ref_cache: &mut RefCache) -> Result<DataType> {
238244
SchemaKind::AllOf { .. } => Err(Error::unimplemented("AllOf parameter is not supported.")),
239245
SchemaKind::AnyOf { .. } => Err(Error::unimplemented("AnyOf parameter is not supported.")),
240246
SchemaKind::Not { .. } => Err(Error::unimplemented("Not parameter is not supported.")),
241-
SchemaKind::Any(_) => Ok(DataType::Json),
247+
SchemaKind::Any(_) => {
248+
if let Some(content_type) = content_type {
249+
if content_type == "application/json" {
250+
Ok(DataType::Json)
251+
} else if content_type == "application/x-yaml" {
252+
Ok(DataType::Yaml)
253+
} else {
254+
Err(Error::unexpected(format!("Cannot resolve the data type for content_type {} with `any` schema-kind", content_type)))
255+
}
256+
} else {
257+
Err(Error::unexpected("Cannot resolve the data type for any schema-kind with no details on content_type"))
258+
}
259+
},
242260
}
243261
}
244262

245263
pub fn ref_or_schema_type(
246264
ref_or_schema: &ReferenceOr<Schema>,
247265
ref_cache: &mut RefCache,
266+
content_type: Option<&str>
248267
) -> Result<DataType> {
249268
match ref_or_schema {
250269
ReferenceOr::Reference { reference } => ref_type_name(reference, ref_cache),
251-
ReferenceOr::Item(schema) => schema_type(schema, ref_cache),
270+
ReferenceOr::Item(schema) => schema_type(schema, ref_cache, content_type),
252271
}
253272
}
254273

@@ -258,6 +277,6 @@ pub fn ref_or_box_schema_type(
258277
) -> Result<DataType> {
259278
match ref_or_schema {
260279
ReferenceOr::Reference { reference } => ref_type_name(reference, ref_cache),
261-
ReferenceOr::Item(schema) => schema_type(schema, ref_cache),
280+
ReferenceOr::Item(schema) => schema_type(schema, ref_cache, None),
262281
}
263282
}

0 commit comments

Comments
 (0)