Skip to content

Commit

Permalink
Working conversion with still a few TODO
Browse files Browse the repository at this point in the history
  • Loading branch information
swallez committed Jul 10, 2023
1 parent d39d01a commit ad93d9a
Show file tree
Hide file tree
Showing 6 changed files with 837 additions and 170 deletions.
6 changes: 3 additions & 3 deletions openapi-converter/clients_schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ impl Model {
}

pub fn type_registry(&self) -> TypeRegistry {
TypeRegistry::new(self)
TypeRegistry::new(&self.types)
}
}

Expand Down Expand Up @@ -793,8 +793,8 @@ pub struct TypeRegistry<'a> {
}

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

Expand Down
44 changes: 44 additions & 0 deletions openapi-converter/clients_schema_to_openapi/src/components.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use openapiv3::{Components, Parameter, ReferenceOr, RequestBody, Response, Schema, StatusCode};
use clients_schema::{TypeDefinition, TypeName, TypeRegistry};
use crate::schemas::SchemaName;

pub struct TypesAndComponents<'a> {
pub types: TypeRegistry<'a>,
pub components: &'a mut Components,
}

impl <'a> TypesAndComponents<'a> {
pub fn new(types_vec: &'a Vec<TypeDefinition>, components: &'a mut Components) -> TypesAndComponents<'a> {
TypesAndComponents {
types: TypeRegistry::new(types_vec),
components,
}
}

pub fn add_request_body(&mut self, endpoint: &str, body: RequestBody,) -> ReferenceOr<RequestBody> {
self.components.request_bodies.insert(endpoint.to_string(), ReferenceOr::Item(body));
ReferenceOr::Reference {
reference: format!("#/components/requestBodies/{}", endpoint)
}
}

pub fn add_parameter(&mut self, endpoint: &str, param: Parameter) -> ReferenceOr<Parameter> {
let result = ReferenceOr::Reference {
reference: format!("#/components/parameters/{}#{}", endpoint, &param.parameter_data_ref().name)
};
self.components.parameters.insert(format!("{}#{}", endpoint, &param.parameter_data_ref().name), ReferenceOr::Item(param));
result
}

pub fn add_response(&mut self, endpoint: &str, status: StatusCode, response: Response) -> ReferenceOr<Response> {
self.components.responses.insert(format!("{}#{}", endpoint, status), ReferenceOr::Item(response));
ReferenceOr::Reference {
reference: format!("#/components/responses/{}#{}", endpoint, status)
}
}

pub fn add_schema(&mut self, name: &TypeName, schema: ReferenceOr<Schema>) -> ReferenceOr<Schema> {
self.components.schemas.insert(name.schema_name(), schema);
name.schema_ref()
}
}
112 changes: 68 additions & 44 deletions openapi-converter/clients_schema_to_openapi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,91 @@
mod paths;
mod schemas;
mod components;

use std::io::Write;
use std::path::Path;
use openapiv3::{Components, OpenAPI};

use clients_schema::{Model, Property, TypeDefinition, TypeName, TypeRegistry, ValueOf};
use clients_schema::{Endpoint, Model};
use crate::components::TypesAndComponents;

pub fn convert_schema(path: impl AsRef<Path>, out: impl Write) -> anyhow::Result<()> {
pub fn convert_schema_file(path: impl AsRef<Path>, endpoint_filter: fn(e: &Endpoint) -> bool, out: impl Write) -> anyhow::Result<()> {
let file = std::fs::File::open(path)?;

let model: Model = serde_json::from_reader(file)?;
let types = model.type_registry();

let mut openapi = openapiv3::OpenAPI::default();

openapi.openapi = "3.1.0".into();
let openapi = convert_schema(&model, endpoint_filter)?;

openapi.info = openapiv3::Info {
title: "Elasticsearch API".to_string(),
description: None,
terms_of_service: None,
contact: None,
license: license(&model),
version: "".to_string(),
extensions: Default::default(),
};
serde_json::to_writer_pretty(out, &openapi)?;
Ok(())
}

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

openapi.paths = openapiv3::Paths {
paths: paths,
let mut openapi = OpenAPI {
openapi: "3.0.3".into(),
info: info(model),
servers: vec![],
paths: Default::default(),
components: Some(Components {
security_schemes: Default::default(),
// Filled from endpoints
responses: Default::default(),
// Filled from endpoints
// TODO: add common request parameters and common cat parameters?
parameters: Default::default(),
examples: Default::default(),
// Filled from endpoints
request_bodies: Default::default(),
headers: Default::default(),
// Filled with type definitions
schemas: Default::default(),
links: Default::default(),
callbacks: Default::default(),
extensions: Default::default(),
}),
security: None,
tags: vec![],
external_docs: None,
extensions: Default::default(),
};

// Types
let components = openapiv3::Components {
security_schemes: Default::default(),
responses: Default::default(),
parameters: Default::default(),
examples: Default::default(),
request_bodies: Default::default(),
headers: Default::default(),
schemas: Default::default(),
links: Default::default(),
callbacks: Default::default(),
extensions: Default::default(),
};
let mut tac = TypesAndComponents::new(&model.types, openapi.components.as_mut().unwrap());

openapi.components = Some(components);
// Endpoints
for endpoint in model.endpoints.iter().filter(|e| endpoint_filter(e)) {
paths::add_endpoint(endpoint, &mut tac, &mut openapi.paths)?;
}
//let paths = paths::build_paths(model.endpoints, &types)?;

serde_json::to_writer_pretty(out, &openapi)?;
Ok(())
//openapi.paths = openapiv3::Paths {
// paths: paths,
// extensions: Default::default(),
//};

Ok(openapi)
}

fn license(model: &Model) -> Option<openapiv3::License> {
if let Some(info) = &model.info {
Some(openapiv3::License {
name: info.license.name.clone(),
url: Some(info.license.url.clone()),
extensions: Default::default(),
})
fn info(model: &Model) -> openapiv3::Info {
let (title, license) = if let Some(info) = &model.info {
(
info.title.clone(),
Some(openapiv3::License {
name: info.license.name.clone(),
url: Some(info.license.url.clone()),
extensions: Default::default(),
})
)
} else {
None
("".to_string(), None)
};

openapiv3::Info {
title,
description: None,
terms_of_service: None,
contact: None,
license,
version: "".to_string(), // TODO
extensions: Default::default(),
}
}
19 changes: 15 additions & 4 deletions openapi-converter/clients_schema_to_openapi/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
fn main() {
clients_schema_to_openapi::convert_schema(
"../../elasticsearch-specification/output/schema/schema.json",
use tracing::Level;
use tracing_subscriber::FmtSubscriber;

fn main() -> anyhow::Result<()> {

let subscriber = FmtSubscriber::builder()
.with_max_level(Level::TRACE)
.finish();
tracing::subscriber::set_global_default(subscriber)?;

clients_schema_to_openapi::convert_schema_file(
"../output/schema/schema-no-generics.json",
|e| e.name == "search",
std::io::stdout()
).unwrap();
)?;

Ok(())
}
Loading

0 comments on commit ad93d9a

Please sign in to comment.