Skip to content

Commit 6db840d

Browse files
swallezlcawl
authored andcommitted
[OpenAPI] Merge multiple paths in a single operation (#4415)
1 parent 0433798 commit 6db840d

File tree

8 files changed

+269
-205
lines changed

8 files changed

+269
-205
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
@@ -229,6 +229,67 @@ pub fn add_endpoint(
229229
// TODO: add error responses
230230
};
231231

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

compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.

0 commit comments

Comments
 (0)