Skip to content

Commit 588f979

Browse files
authored
[OpenAPI] Merge multiple paths in a single operation (#4415)
1 parent b48894f commit 588f979

File tree

7 files changed

+263
-199
lines changed

7 files changed

+263
-199
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ transform-to-openapi: ## Generate the OpenAPI definition from the compiled schem
5555
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --output output/openapi/elasticsearch-openapi.json
5656
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --output output/openapi/elasticsearch-serverless-openapi.json
5757

58+
transform-to-openapi-for-docs: ## Generate the OpenAPI definition tailored for API docs generation
59+
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --lift-enum-descriptions --merge-multipath-endpoints --output output/openapi/elasticsearch-openapi-docs.json
60+
5861
filter-for-serverless: ## Generate the serverless version from the compiled schema
5962
@npm run --prefix compiler filter-by-availability -- --serverless --visibility=public --input ../output/schema/schema.json --output ../output/output/openapi/elasticsearch-serverless-openapi.json
6063

compiler-rs/clients_schema_to_openapi/src/cli.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ pub struct Cli {
2020
#[argh(option, default = "SchemaFlavor::All")]
2121
pub flavor: SchemaFlavor,
2222

23-
/// add enum descriptions to property descriptions [default = true]
24-
#[argh(option, default = "true")]
25-
pub lift_enum_descriptions: bool,
26-
2723
/// generate only this namespace (can be repeated)
2824
#[argh(option)]
2925
pub namespace: Vec<String>,
26+
27+
/// add enum descriptions to property descriptions [default = true]
28+
#[argh(switch)]
29+
pub lift_enum_descriptions: bool,
30+
31+
/// merge endpoints with multiple paths into a single OpenAPI operation [default = false]
32+
#[argh(switch)]
33+
pub merge_multipath_endpoints: bool,
3034
}
3135

3236
use derive_more::FromStr;
@@ -42,20 +46,21 @@ pub enum SchemaFlavor {
4246
}
4347

4448
impl From<Cli> for Configuration {
45-
fn from(val: Cli) -> Configuration {
46-
let flavor = match val.flavor {
49+
fn from(cli: Cli) -> Configuration {
50+
let flavor = match cli.flavor {
4751
SchemaFlavor::All => None,
4852
SchemaFlavor::Serverless => Some(Flavor::Serverless),
4953
SchemaFlavor::Stack => Some(Flavor::Stack),
5054
};
5155

5256
Configuration {
5357
flavor,
54-
lift_enum_descriptions: val.lift_enum_descriptions,
55-
namespaces: if val.namespace.is_empty() {
58+
lift_enum_descriptions: cli.lift_enum_descriptions,
59+
merge_multipath_endpoints: cli.merge_multipath_endpoints,
60+
namespaces: if cli.namespace.is_empty() {
5661
None
5762
} else {
58-
Some(val.namespace)
63+
Some(cli.namespace)
5964
},
6065
}
6166
}

compiler-rs/clients_schema_to_openapi/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@ use crate::components::TypesAndComponents;
3232
pub struct Configuration {
3333
pub flavor: Option<Flavor>,
3434
pub namespaces: Option<Vec<String>>,
35+
36+
/// If a property value is an enumeration, the description of possible values will be copied in the
37+
/// property's description (also works for arrays of enums).
3538
pub lift_enum_descriptions: bool,
39+
40+
/// Will output endpoints having multiple paths into a single operation. The operation's path will
41+
/// be the longest one (with values for all optional parameters), and the other paths will be added
42+
/// at the beginning of the operation's description.
43+
pub merge_multipath_endpoints: bool,
3644
}
3745

3846
/// Convert an API model into an OpenAPI v3 schema, optionally filtered for a given flavor

compiler-rs/clients_schema_to_openapi/src/paths.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,67 @@ pub fn add_endpoint(
232232
// TODO: add error responses
233233
};
234234

235+
//---- Merge multipath endpoints if asked for
236+
let mut new_endpoint: clients_schema::Endpoint;
237+
238+
let endpoint = if is_multipath && tac.config.merge_multipath_endpoints {
239+
new_endpoint = endpoint.clone();
240+
let endpoint = &mut new_endpoint;
241+
242+
// Sort paths from smallest to longest
243+
endpoint.urls.sort_by_key(|x| x.path.len());
244+
245+
// Keep the longest and its last method so that the operation's path+method are the same as the last one
246+
// (avoids the perception that it may have been chosen randomly).
247+
let mut longest_path = endpoint.urls.last().unwrap().clone();
248+
while longest_path.methods.len() > 1 {
249+
longest_path.methods.remove(0);
250+
}
251+
252+
// Replace endpoint urls with the longest path
253+
let mut urls = vec![longest_path];
254+
std::mem::swap(&mut endpoint.urls, &mut urls);
255+
256+
let split_desc = split_summary_desc(&endpoint.description);
257+
258+
// Make sure the description is stays at the top
259+
let mut description = match split_desc.summary {
260+
Some(summary) => format!("{summary}\n\n"),
261+
None => String::new(),
262+
};
263+
264+
// Convert removed paths to descriptions
265+
write!(description, "**All methods and paths for this operation:**\n\n")?;
266+
267+
for url in urls {
268+
for method in url.methods {
269+
let lower_method = method.to_lowercase();
270+
let path = &url.path;
271+
write!(
272+
description,
273+
r#"<div>
274+
<span class="operation-verb {lower_method}">{method}</span>
275+
<span class="operation-path">{path}</span>
276+
</div>
277+
"#
278+
)?;
279+
}
280+
}
281+
282+
if let Some(desc) = &split_desc.description {
283+
write!(description, "\n\n{}", desc)?;
284+
}
285+
286+
// Replace description
287+
endpoint.description = description;
288+
289+
// Done
290+
endpoint
291+
} else {
292+
// Not multipath or not asked to merge multipath
293+
endpoint
294+
};
295+
235296
//---- Build a path for each url + method
236297
let mut operation_counter = 0;
237298

Binary file not shown.

0 commit comments

Comments
 (0)