1use openapiv3::OpenAPI;
2
3mod highway;
4mod printer;
5
6#[cfg(test)]
7pub mod test;
8
9use printer::Printable;
10
11pub enum Format {
13 Yaml,
14 Json,
15}
16
17#[derive(Debug)]
19pub enum Error {
20 InvalidSource,
21}
22
23impl std::fmt::Display for Error {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 Self::InvalidSource => write!(f, "OpenAPI structure cannot be parsed"),
27 }
28 }
29}
30
31impl std::error::Error for Error {}
32
33pub fn to_string(source: &str, format: Format) -> Result<String, Error> {
35 let api: OpenAPI = match format {
36 Format::Yaml => serde_yaml::from_str(&source).map_err(|_| Error::InvalidSource)?,
37 Format::Json => serde_json::from_str(&source).map_err(|_| Error::InvalidSource)?,
38 };
39
40 let mut highway_components = highway::Components::new();
43
44 if let Some(components) = api.components {
45 for (name, schema) in components.schemas.iter() {
57 if let Err(reason) = highway_components.parse_schema(&name, &schema) {
58 eprintln!("Failed {} {:#?}", name, reason);
59 }
60 }
61 }
62
63 println!("{:#?}", highway_components);
64
65 let mut generated: printer::GeneratedModule = highway_components.into();
66
67 generated.api.set_name(api.info.title);
68 generated.api.set_description(api.info.description);
69 generated
70 .api
71 .set_terms_of_service(api.info.terms_of_service);
72
73 Ok(format!("{}", generated.print()))
74}
75
76#[cfg(test)]
77mod tests {
78 use super::{to_string, Format};
79 use crate::test::pretty;
80 use insta::assert_snapshot;
81
82 #[test]
83 fn yaml_schema_prints() {
84 let schema = r###"
85openapi: 3.0.1
86info:
87 title: Demo API.
88 version: 0.1.0
89 description: Test api
90paths:
91 "/stub":
92 get:
93 operationId: stub
94 responses:
95 303:
96 description: "Stub"
97
98components:
99 schemas:
100 SessionUser:
101 description: Current user in a session
102 type: object
103 required:
104 - firstName
105 - lastName
106 properties:
107 firstName:
108 type: string
109 lastName:
110 type: string
111 inner:
112 type: object
113 properties:
114 foo:
115 type: number
116 bar:
117 type: integer
118 baz:
119 type: object
120 properties:
121 demo:
122 type: string
123 required:
124 - baz
125 - bar
126 "###;
127
128 assert_snapshot!(pretty(to_string(&schema, Format::Yaml).unwrap()), @r###"
129 #![allow(dead_code, unused_imports)]
130 pub mod api {
131 #[doc = "Test api"]
132 pub struct DemoApi {
133 api: actix_swagger::Api,
134 }
135 impl DemoApi {
136 pub fn new() -> Self {
137 Self {
138 api: actix_swagger::Api::new(),
139 }
140 }
141 }
142 impl Default for DemoApi {
143 fn default() -> Self {
144 let api = Self::new();
145 api
146 }
147 }
148 impl actix_web::dev::HttpServiceFactory for DemoApi {
149 fn register(self, config: &mut actix_web::dev::AppService) {
150 self.api.register(config);
151 }
152 }
153 use super::paths;
154 use actix_swagger::{Answer, Method};
155 use actix_web::{dev::Factory, FromRequest};
156 use std::future::Future;
157 impl DemoApi {}
158 }
159 pub mod components {
160 pub mod parameters {
161 use serde::{Deserialize, Serialize};
162 }
163 pub mod request_bodies {
164 use serde::{Deserialize, Serialize};
165 }
166 pub mod responses {
167 use serde::{Deserialize, Serialize};
168 }
169 pub mod schemas {
170 use serde::{Deserialize, Serialize};
171 #[doc = "Current user in a session"]
172 #[derive(Debug, Serialize, Deserialize)]
173 pub struct SessionUser {
174 #[serde(rename = "firstName")]
175 pub first_name: String,
176 #[serde(rename = "lastName")]
177 pub last_name: String,
178 pub inner: Option<SessionUserInner>,
179 }
180 #[derive(Debug, Serialize, Deserialize)]
181 pub struct SessionUserInner {
182 pub foo: Option<f32>,
183 pub bar: i32,
184 pub baz: SessionUserInnerBaz,
185 }
186 #[derive(Debug, Serialize, Deserialize)]
187 pub struct SessionUserInnerBaz {
188 pub demo: Option<String>,
189 }
190 }
191 }
192 pub mod paths {
193 use super::components::{parameters, responses};
194 }
195 "###);
196 }
197}