Skip to content

Commit c2b7f80

Browse files
authored
[OpenAPI] Merge multiple paths in a single operation (#4415) (#4499)
1 parent 1faae3d commit c2b7f80

File tree

7 files changed

+258
-194
lines changed

7 files changed

+258
-194
lines changed

Makefile

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

55+
transform-to-openapi-for-docs: ## Generate the OpenAPI definition tailored for API docs generation
56+
@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
57+
5558
filter-for-serverless: ## Generate the serverless version from the compiled schema
5659
@npm run --prefix compiler filter-by-availability -- --serverless --visibility=public --input ../output/schema/schema.json --output ../output/output/openapi/elasticsearch-serverless-openapi.json
5760

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
@@ -31,7 +31,15 @@ use crate::components::TypesAndComponents;
3131
pub struct Configuration {
3232
pub flavor: Option<Flavor>,
3333
pub namespaces: Option<Vec<String>>,
34+
35+
/// If a property value is an enumeration, the description of possible values will be copied in the
36+
/// property's description (also works for arrays of enums).
3437
pub lift_enum_descriptions: bool,
38+
39+
/// Will output endpoints having multiple paths into a single operation. The operation's path will
40+
/// be the longest one (with values for all optional parameters), and the other paths will be added
41+
/// at the beginning of the operation's description.
42+
pub merge_multipath_endpoints: bool,
3543
}
3644

3745
/// 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
@@ -228,6 +228,67 @@ pub fn add_endpoint(
228228
// TODO: add error responses
229229
};
230230

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

Binary file not shown.

0 commit comments

Comments
 (0)