Skip to content

Commit e99d69a

Browse files
swallezAnaethelion
authored andcommitted
Output the public API only in the stack OpenAPI schema (#3308)
* Output the public API only in the stack OpenAPI schema * Fix comment * Refactor OpenAPI conversion to define filters in a single place (cherry picked from commit bd35837)
1 parent 1ea2583 commit e99d69a

File tree

5 files changed

+39
-658
lines changed

5 files changed

+39
-658
lines changed

compiler-rs/clients_schema_to_openapi/src/lib.rs

+24-36
Original file line numberDiff line numberDiff line change
@@ -20,57 +20,45 @@ mod paths;
2020
mod schemas;
2121
mod utils;
2222

23-
use std::collections::HashSet;
24-
use std::io::{BufWriter, Write};
25-
use std::path::Path;
2623
use indexmap::IndexMap;
2724

28-
use clients_schema::{Availabilities, Endpoint, IndexedModel, Stability};
25+
use clients_schema::{Availabilities, Flavor, IndexedModel, Stability, Visibility};
2926
use openapiv3::{Components, OpenAPI};
30-
use tracing::warn;
31-
27+
use clients_schema::transform::ExpandConfig;
3228
use crate::components::TypesAndComponents;
3329

34-
pub fn convert_schema_file(
35-
path: impl AsRef<Path>,
36-
filter: Option<fn(&Option<Availabilities>) -> bool>,
37-
endpoint_filter: fn(e: &Endpoint) -> bool,
38-
out: impl Write,
39-
) -> anyhow::Result<()> {
40-
// Parsing from a string is faster than using a buffered reader when there is a need for look-ahead
41-
// See https://github.com/serde-rs/json/issues/160
42-
let json = &std::fs::read_to_string(path)?;
43-
let json_deser = &mut serde_json::Deserializer::from_str(json);
44-
45-
let mut unused = HashSet::new();
46-
let mut model: IndexedModel = serde_ignored::deserialize(json_deser, |path| {
47-
if let serde_ignored::Path::Map { parent: _, key } = path {
48-
unused.insert(key);
49-
}
50-
})?;
51-
if !unused.is_empty() {
52-
let msg = unused.into_iter().collect::<Vec<_>>().join(", ");
53-
warn!("Unknown fields found in schema.json: {}", msg);
54-
}
30+
/// Convert an API model into an OpenAPI v3 schema, optionally filtered for a given flavor
31+
pub fn convert_schema(mut schema: IndexedModel, flavor: Option<Flavor>) -> anyhow::Result<OpenAPI> {
32+
// Expand generics
33+
schema = clients_schema::transform::expand_generics(schema, ExpandConfig::default())?;
34+
35+
// Filter flavor
36+
let filter: Option<fn(&Option<Availabilities>) -> bool> = match flavor {
37+
None => None,
38+
Some(Flavor::Stack) => Some(|a| {
39+
// Generate only public items for Stack
40+
Flavor::Stack.visibility(a) == Some(Visibility::Public)
41+
}),
42+
Some(Flavor::Serverless) => Some(|a| {
43+
// Generate only public items for Serverless
44+
Flavor::Serverless.visibility(a) == Some(Visibility::Public)
45+
}),
46+
};
5547

5648
if let Some(filter) = filter {
57-
model = clients_schema::transform::filter_availability(model, filter)?;
49+
schema = clients_schema::transform::filter_availability(schema, filter)?;
5850
}
5951

60-
model.endpoints.retain(endpoint_filter);
61-
62-
let openapi = convert_schema(&model)?;
63-
serde_json::to_writer_pretty(BufWriter::new(out), &openapi)?;
64-
Ok(())
52+
convert_expanded_schema(&schema)
6553
}
6654

67-
/// Convert an API model into an OpenAPI v3 schema. The input model must have all generics expanded, converstion
55+
/// Convert an API model into an OpenAPI v3 schema. The input model must have all generics expanded, conversion
6856
/// will fail otherwise.
6957
///
70-
/// Note: there are ways to represent [generics in JSON Schema], but its unlikely that tooling will understood it.
58+
/// Note: there are ways to represent [generics in JSON Schema], but its unlikely that tooling will understand it.
7159
///
7260
/// [generics in JSON Schema]: https://json-schema.org/blog/posts/dynamicref-and-generics
73-
pub fn convert_schema(model: &IndexedModel) -> anyhow::Result<OpenAPI> {
61+
pub fn convert_expanded_schema(model: &IndexedModel) -> anyhow::Result<OpenAPI> {
7462
let mut openapi = OpenAPI {
7563
openapi: "3.0.3".into(),
7664
info: info(model),

compiler-rs/clients_schema_to_openapi/src/main.rs

+8-23
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::path::{Path, PathBuf};
1919
use anyhow::bail;
2020

2121
use clap::{Parser, ValueEnum};
22-
use clients_schema::{Availabilities, Visibility};
22+
use clients_schema::Flavor;
2323
use tracing::Level;
2424
use tracing_subscriber::fmt::format::FmtSpan;
2525
use tracing_subscriber::FmtSubscriber;
@@ -72,33 +72,18 @@ impl Cli {
7272
std::fs::read_to_string(self.schema)?
7373
};
7474

75-
let mut model: clients_schema::IndexedModel = match serde_json::from_str(&json) {
75+
let model: clients_schema::IndexedModel = match serde_json::from_str(&json) {
7676
Ok(indexed_model) => indexed_model,
7777
Err(e) => bail!("cannot parse schema json: {}", e)
7878
};
7979

80-
if let Some(flavor) = self.flavor {
81-
if flavor != SchemaFlavor::All {
82-
let filter: fn(&Option<Availabilities>) -> bool = match flavor {
83-
SchemaFlavor::All => |_| true,
84-
SchemaFlavor::Stack => |a| {
85-
// Generate public and private items for Stack
86-
clients_schema::Flavor::Stack.available(a)
87-
},
88-
SchemaFlavor::Serverless => |a| {
89-
// Generate only public items for Serverless
90-
clients_schema::Flavor::Serverless.visibility(a) == Some(Visibility::Public)
91-
},
92-
};
93-
94-
use clients_schema::transform::*;
95-
96-
model = expand_generics(model, ExpandConfig::default())?;
97-
model = filter_availability(model, filter)?;
98-
}
99-
}
80+
let flavor = match self.flavor {
81+
Some(SchemaFlavor::All) | None => None,
82+
Some(SchemaFlavor::Stack) => Some(Flavor::Stack),
83+
Some(SchemaFlavor::Serverless) => Some(Flavor::Serverless),
84+
};
10085

101-
let openapi = clients_schema_to_openapi::convert_schema(&model)?;
86+
let openapi = clients_schema_to_openapi::convert_schema(model, flavor)?;
10287

10388
let output: Box<dyn std::io::Write> = {
10489
if let Some(output) = self.output {
Binary file not shown.

compiler-rs/compiler-wasm-lib/src/lib.rs

+6-17
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616
// under the License.
1717

1818
use anyhow::bail;
19-
use clients_schema::{Availabilities, Visibility};
19+
use clients_schema::{Flavor, IndexedModel};
2020
use wasm_bindgen::prelude::*;
21-
use clients_schema::transform::ExpandConfig;
2221

2322
#[wasm_bindgen]
2423
pub fn convert_schema_to_openapi(json: &str, flavor: &str) -> Result<String, String> {
@@ -27,25 +26,15 @@ pub fn convert_schema_to_openapi(json: &str, flavor: &str) -> Result<String, Str
2726
}
2827

2928
fn convert0(json: &str, flavor: &str) -> anyhow::Result<String> {
30-
let filter: Option<fn(&Option<Availabilities>) -> bool> = match flavor {
29+
let flavor = match flavor {
3130
"all" => None,
32-
"stack" => Some(|a| {
33-
// Generate public and private items for Stack
34-
clients_schema::Flavor::Stack.available(a)
35-
}),
36-
"serverless" => Some(|a| {
37-
// Generate only public items for Serverless
38-
clients_schema::Flavor::Serverless.visibility(a) == Some(Visibility::Public)
39-
}),
31+
"stack" => Some(Flavor::Stack),
32+
"serverless" => Some(Flavor::Serverless),
4033
_ => bail!("Unknown flavor {}", flavor),
4134
};
4235

43-
let mut schema = clients_schema::IndexedModel::from_reader(json.as_bytes())?;
44-
schema = clients_schema::transform::expand_generics(schema, ExpandConfig::default())?;
45-
if let Some(filter) = filter {
46-
schema = clients_schema::transform::filter_availability(schema, filter)?;
47-
}
48-
let openapi = clients_schema_to_openapi::convert_schema(&schema)?;
36+
let schema = IndexedModel::from_reader(json.as_bytes())?;
37+
let openapi = clients_schema_to_openapi::convert_schema(schema, flavor)?;
4938
let result = serde_json::to_string_pretty(&openapi)?;
5039
Ok(result)
5140
}

0 commit comments

Comments
 (0)