ohkami_openapi/
lib.rs

1#![allow(non_snake_case, non_camel_case_types)]
2
3#[cfg(test)]
4mod _test;
5mod _util;
6
7pub mod schema;
8pub use schema::SchemaRef;
9
10pub mod security;
11pub use security::SecurityScheme;
12
13pub mod request;
14pub use request::{Parameter, RequestBody};
15
16pub mod response;
17pub use response::{Response, Responses, Status};
18
19pub mod paths;
20pub use paths::Operation;
21
22pub mod document;
23
24pub enum Inbound {
25    None,
26    Param(Parameter),
27    Params(Vec<Parameter>),
28    Body(RequestBody),
29    Security {
30        scheme: SecurityScheme,
31        scopes: &'static [&'static str],
32    },
33}
34
35/// handle the `schema` as a component schema named `name`.
36/// This is useful for reusing schemas in the OpenAPI document.
37pub fn component<T: schema::Type::SchemaType>(
38    name: &'static str,
39    schema: schema::Schema<T>,
40) -> schema::Schema<T> {
41    schema::Schema::component(name, schema)
42}
43
44/// `type: string`
45pub fn string() -> schema::Schema<schema::Type::string> {
46    schema::Schema::string()
47}
48/// `type: number`
49pub fn number() -> schema::Schema<schema::Type::number> {
50    schema::Schema::number()
51}
52/// `type: integer`
53pub fn integer() -> schema::Schema<schema::Type::integer> {
54    schema::Schema::integer()
55}
56/// `type: boolean`
57pub fn bool() -> schema::Schema<schema::Type::bool> {
58    schema::Schema::bool()
59}
60/// ```txt
61/// type: array
62/// items:
63///   type: ###`items`'s schema###
64/// ```
65pub fn array(items: impl Into<schema::SchemaRef>) -> schema::Schema<schema::Type::array> {
66    schema::Schema::array(items)
67}
68/// `type: object`
69pub fn object() -> schema::Schema<schema::Type::object> {
70    schema::Schema::object()
71}
72/// `anyOf: [...{schemas}]`
73pub fn any_of(schemas: impl schema::SchemaList) -> schema::Schema<schema::Type::any> {
74    schema::Schema::any_of(schemas)
75}
76/// `allOf: [...{schemas}]`
77pub fn all_of(schemas: impl schema::SchemaList) -> schema::Schema<schema::Type::any> {
78    schema::Schema::all_of(schemas)
79}
80/// `oneOf: [...{schemas}]`
81pub fn one_of(schemas: impl schema::SchemaList) -> schema::Schema<schema::Type::any> {
82    schema::Schema::one_of(schemas)
83}
84
85/// # OpenAPI Schema trait
86///
87/// ## Required
88///
89/// - `schema() -> impl Into<schema::SchemaRef>`
90///   - this `impl Into<schema::SchemaRef>` mostly means `schema::Schema<{something}>`.
91///
92/// ## Implementation Notes
93///
94/// Generally, you can implement this trait for your types by `#[derive(Schema)]`.
95/// See it's documentation for more details.
96///
97/// But of course, you can implement it manually if you want to.
98/// In that case, start from **base schemas**:
99///
100/// - [`string()`](fn@string)
101/// - [`number()`](fn@number)
102/// - [`integer()`](fn@integer)
103/// - [`bool()`](fn@bool)
104/// - [`array({items})`](fn@array)
105/// - [`object()`](fn@object)
106/// - [`any_of({schemas})`](fn@any_of)
107/// - [`all_of({schemas})`](fn@all_of)
108/// - [`one_of({schemas})`](fn@one_of)
109///
110/// and, [`component({name}, {schema})`](fn@component) if you want to name and reuse
111/// the schema in the OpenAPI document.
112///
113/// ## Example
114///
115/// ```rust,ignore
116/// use ohkami::openapi;
117///
118/// #[derive(openapi::Schema)]
119/// struct MySchema {
120///     pub id: u32,
121///     pub name: String,
122///     pub age: Option<u8>,
123/// }
124/// /* equivalent to: */
125/// impl openapi::Schema for MySchema {
126///     fn schema() -> impl Into<openapi::schema::SchemaRef> {
127///         openapi::object()
128///             .property("id", openapi::integer().format("uint32"))
129///             .property("name", openapi::string())
130///             .optional("age", openapi::integer().format("uint8"))
131///     }
132/// }
133///
134/// #[derive(openapi::Schema)]
135/// #[openapi(component)]
136/// struct MyComponentSchema {
137///     pub id: u32,
138///     pub name: String,
139///     pub age: Option<u8>,
140/// }
141/// /* equivalent to: */
142/// impl openapi::Schema for MyComponentSchema {
143///     fn schema() -> impl Into<openapi::schema::SchemaRef> {
144///         openapi::component("MyComponentSchema",  openapi::object()
145///             .property("id", openapi::integer().format("uint32"))
146///             .property("name", openapi::string())
147///             .optional("age", openapi::integer().format("uint8"))
148///         )
149///     }
150/// }
151/// ```
152///
153/// ## Default Implementations
154///
155/// - `str`, `String`
156/// - `u8`, `u16`, `u32`, `u64`, `usize`
157/// - `i8`, `i16`, `i32`, `i64`, `isize`
158/// - `f32`, `f64`
159/// - `uuid::Uuid`
160/// - `Vec<S>`, `[S]`, `[S; N]`, `Cow<'_, S>`, `Arc<S>`, `&S` where `S: Schema`
161pub trait Schema {
162    fn schema() -> impl Into<schema::SchemaRef>;
163}
164const _: () = {
165    impl Schema for str {
166        fn schema() -> impl Into<schema::SchemaRef> {
167            string()
168        }
169    }
170    impl Schema for String {
171        fn schema() -> impl Into<schema::SchemaRef> {
172            string()
173        }
174    }
175
176    impl Schema for u8 {
177        fn schema() -> impl Into<schema::SchemaRef> {
178            integer().format("uint8")
179        }
180    }
181    impl Schema for u16 {
182        fn schema() -> impl Into<schema::SchemaRef> {
183            integer().format("uint16")
184        }
185    }
186    impl Schema for u32 {
187        fn schema() -> impl Into<schema::SchemaRef> {
188            integer().format("uint32")
189        }
190    }
191    impl Schema for u64 {
192        fn schema() -> impl Into<schema::SchemaRef> {
193            integer().format("uint64")
194        }
195    }
196    impl Schema for usize {
197        fn schema() -> impl Into<schema::SchemaRef> {
198            integer()
199        }
200    }
201
202    impl Schema for i8 {
203        fn schema() -> impl Into<schema::SchemaRef> {
204            integer().format("int8")
205        }
206    }
207    impl Schema for i16 {
208        fn schema() -> impl Into<schema::SchemaRef> {
209            integer().format("int16")
210        }
211    }
212    impl Schema for i32 {
213        fn schema() -> impl Into<schema::SchemaRef> {
214            integer().format("int32")
215        }
216    }
217    impl Schema for i64 {
218        fn schema() -> impl Into<schema::SchemaRef> {
219            integer().format("int64")
220        }
221    }
222    impl Schema for isize {
223        fn schema() -> impl Into<schema::SchemaRef> {
224            integer()
225        }
226    }
227
228    impl Schema for f32 {
229        fn schema() -> impl Into<schema::SchemaRef> {
230            number().format("float")
231        }
232    }
233    impl Schema for f64 {
234        fn schema() -> impl Into<schema::SchemaRef> {
235            number().format("double")
236        }
237    }
238
239    impl Schema for uuid::Uuid {
240        fn schema() -> impl Into<schema::SchemaRef> {
241            string().format("uuid")
242        }
243    }
244
245    impl<S: Schema> Schema for Vec<S> {
246        fn schema() -> impl Into<schema::SchemaRef> {
247            array(S::schema())
248        }
249    }
250    impl<S: Schema> Schema for [S] {
251        fn schema() -> impl Into<schema::SchemaRef> {
252            array(S::schema())
253        }
254    }
255    impl<const N: usize, S: Schema> Schema for [S; N] {
256        fn schema() -> impl Into<schema::SchemaRef> {
257            array(S::schema())
258        }
259    }
260
261    impl<S: Schema + ToOwned + ?Sized> Schema for std::borrow::Cow<'_, S> {
262        fn schema() -> impl Into<schema::SchemaRef> {
263            S::schema()
264        }
265    }
266    impl<S: Schema + ?Sized> Schema for std::sync::Arc<S> {
267        fn schema() -> impl Into<schema::SchemaRef> {
268            S::schema()
269        }
270    }
271
272    impl<S: Schema + ?Sized> Schema for &S {
273        fn schema() -> impl Into<schema::SchemaRef> {
274            S::schema()
275        }
276    }
277};