Skip to content

Commit ad93d9a

Browse files
committed
Working conversion with still a few TODO
1 parent d39d01a commit ad93d9a

File tree

6 files changed

+837
-170
lines changed

6 files changed

+837
-170
lines changed

openapi-converter/clients_schema/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ impl Model {
750750
}
751751

752752
pub fn type_registry(&self) -> TypeRegistry {
753-
TypeRegistry::new(self)
753+
TypeRegistry::new(&self.types)
754754
}
755755
}
756756

@@ -793,8 +793,8 @@ pub struct TypeRegistry<'a> {
793793
}
794794

795795
impl<'a> TypeRegistry<'a> {
796-
pub fn new(model: &Model) -> TypeRegistry {
797-
let types = model.types.iter()
796+
pub fn new(types_vec: &Vec<TypeDefinition>) -> TypeRegistry {
797+
let types = types_vec.iter()
798798
.map(|typedef| (typedef.name(), typedef))
799799
.collect::<HashMap<_,_>>();
800800

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use openapiv3::{Components, Parameter, ReferenceOr, RequestBody, Response, Schema, StatusCode};
2+
use clients_schema::{TypeDefinition, TypeName, TypeRegistry};
3+
use crate::schemas::SchemaName;
4+
5+
pub struct TypesAndComponents<'a> {
6+
pub types: TypeRegistry<'a>,
7+
pub components: &'a mut Components,
8+
}
9+
10+
impl <'a> TypesAndComponents<'a> {
11+
pub fn new(types_vec: &'a Vec<TypeDefinition>, components: &'a mut Components) -> TypesAndComponents<'a> {
12+
TypesAndComponents {
13+
types: TypeRegistry::new(types_vec),
14+
components,
15+
}
16+
}
17+
18+
pub fn add_request_body(&mut self, endpoint: &str, body: RequestBody,) -> ReferenceOr<RequestBody> {
19+
self.components.request_bodies.insert(endpoint.to_string(), ReferenceOr::Item(body));
20+
ReferenceOr::Reference {
21+
reference: format!("#/components/requestBodies/{}", endpoint)
22+
}
23+
}
24+
25+
pub fn add_parameter(&mut self, endpoint: &str, param: Parameter) -> ReferenceOr<Parameter> {
26+
let result = ReferenceOr::Reference {
27+
reference: format!("#/components/parameters/{}#{}", endpoint, &param.parameter_data_ref().name)
28+
};
29+
self.components.parameters.insert(format!("{}#{}", endpoint, &param.parameter_data_ref().name), ReferenceOr::Item(param));
30+
result
31+
}
32+
33+
pub fn add_response(&mut self, endpoint: &str, status: StatusCode, response: Response) -> ReferenceOr<Response> {
34+
self.components.responses.insert(format!("{}#{}", endpoint, status), ReferenceOr::Item(response));
35+
ReferenceOr::Reference {
36+
reference: format!("#/components/responses/{}#{}", endpoint, status)
37+
}
38+
}
39+
40+
pub fn add_schema(&mut self, name: &TypeName, schema: ReferenceOr<Schema>) -> ReferenceOr<Schema> {
41+
self.components.schemas.insert(name.schema_name(), schema);
42+
name.schema_ref()
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,91 @@
11
mod paths;
22
mod schemas;
3+
mod components;
34

45
use std::io::Write;
56
use std::path::Path;
7+
use openapiv3::{Components, OpenAPI};
68

7-
use clients_schema::{Model, Property, TypeDefinition, TypeName, TypeRegistry, ValueOf};
9+
use clients_schema::{Endpoint, Model};
10+
use crate::components::TypesAndComponents;
811

9-
pub fn convert_schema(path: impl AsRef<Path>, out: impl Write) -> anyhow::Result<()> {
12+
pub fn convert_schema_file(path: impl AsRef<Path>, endpoint_filter: fn(e: &Endpoint) -> bool, out: impl Write) -> anyhow::Result<()> {
1013
let file = std::fs::File::open(path)?;
11-
1214
let model: Model = serde_json::from_reader(file)?;
13-
let types = model.type_registry();
14-
15-
let mut openapi = openapiv3::OpenAPI::default();
1615

17-
openapi.openapi = "3.1.0".into();
16+
let openapi = convert_schema(&model, endpoint_filter)?;
1817

19-
openapi.info = openapiv3::Info {
20-
title: "Elasticsearch API".to_string(),
21-
description: None,
22-
terms_of_service: None,
23-
contact: None,
24-
license: license(&model),
25-
version: "".to_string(),
26-
extensions: Default::default(),
27-
};
18+
serde_json::to_writer_pretty(out, &openapi)?;
19+
Ok(())
20+
}
2821

29-
// Endpoints
30-
let paths = paths::build_paths(&model.endpoints, &types)?;
22+
pub fn convert_schema(model: &Model, endpoint_filter: fn(e: &Endpoint) -> bool) -> anyhow::Result<OpenAPI> {
3123

32-
openapi.paths = openapiv3::Paths {
33-
paths: paths,
24+
let mut openapi = OpenAPI {
25+
openapi: "3.0.3".into(),
26+
info: info(model),
27+
servers: vec![],
28+
paths: Default::default(),
29+
components: Some(Components {
30+
security_schemes: Default::default(),
31+
// Filled from endpoints
32+
responses: Default::default(),
33+
// Filled from endpoints
34+
// TODO: add common request parameters and common cat parameters?
35+
parameters: Default::default(),
36+
examples: Default::default(),
37+
// Filled from endpoints
38+
request_bodies: Default::default(),
39+
headers: Default::default(),
40+
// Filled with type definitions
41+
schemas: Default::default(),
42+
links: Default::default(),
43+
callbacks: Default::default(),
44+
extensions: Default::default(),
45+
}),
46+
security: None,
47+
tags: vec![],
48+
external_docs: None,
3449
extensions: Default::default(),
3550
};
3651

37-
// Types
38-
let components = openapiv3::Components {
39-
security_schemes: Default::default(),
40-
responses: Default::default(),
41-
parameters: Default::default(),
42-
examples: Default::default(),
43-
request_bodies: Default::default(),
44-
headers: Default::default(),
45-
schemas: Default::default(),
46-
links: Default::default(),
47-
callbacks: Default::default(),
48-
extensions: Default::default(),
49-
};
52+
let mut tac = TypesAndComponents::new(&model.types, openapi.components.as_mut().unwrap());
5053

51-
openapi.components = Some(components);
54+
// Endpoints
55+
for endpoint in model.endpoints.iter().filter(|e| endpoint_filter(e)) {
56+
paths::add_endpoint(endpoint, &mut tac, &mut openapi.paths)?;
57+
}
58+
//let paths = paths::build_paths(model.endpoints, &types)?;
5259

53-
serde_json::to_writer_pretty(out, &openapi)?;
54-
Ok(())
60+
//openapi.paths = openapiv3::Paths {
61+
// paths: paths,
62+
// extensions: Default::default(),
63+
//};
64+
65+
Ok(openapi)
5566
}
5667

57-
fn license(model: &Model) -> Option<openapiv3::License> {
58-
if let Some(info) = &model.info {
59-
Some(openapiv3::License {
60-
name: info.license.name.clone(),
61-
url: Some(info.license.url.clone()),
62-
extensions: Default::default(),
63-
})
68+
fn info(model: &Model) -> openapiv3::Info {
69+
let (title, license) = if let Some(info) = &model.info {
70+
(
71+
info.title.clone(),
72+
Some(openapiv3::License {
73+
name: info.license.name.clone(),
74+
url: Some(info.license.url.clone()),
75+
extensions: Default::default(),
76+
})
77+
)
6478
} else {
65-
None
79+
("".to_string(), None)
80+
};
81+
82+
openapiv3::Info {
83+
title,
84+
description: None,
85+
terms_of_service: None,
86+
contact: None,
87+
license,
88+
version: "".to_string(), // TODO
89+
extensions: Default::default(),
6690
}
6791
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1-
fn main() {
2-
clients_schema_to_openapi::convert_schema(
3-
"../../elasticsearch-specification/output/schema/schema.json",
1+
use tracing::Level;
2+
use tracing_subscriber::FmtSubscriber;
3+
4+
fn main() -> anyhow::Result<()> {
5+
6+
let subscriber = FmtSubscriber::builder()
7+
.with_max_level(Level::TRACE)
8+
.finish();
9+
tracing::subscriber::set_global_default(subscriber)?;
10+
11+
clients_schema_to_openapi::convert_schema_file(
12+
"../output/schema/schema-no-generics.json",
13+
|e| e.name == "search",
414
std::io::stdout()
5-
).unwrap();
15+
)?;
616

17+
Ok(())
718
}

0 commit comments

Comments
 (0)