1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#![warn(missing_debug_implementations, rust_2018_idioms)]
#![forbid(unsafe_code)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::tabs_in_doc_comments))]
#![doc = r##"
This crate gives static type information for primitives and commonly used types from the standard
library and a few other commonly used libraries like `chrono` and `uuid`. Also, it provides a
derive macro for structs and enums to gain access to their static type information at runtime.
The core of this crate is the [`OpenapiType`] trait. It has one static function,
[`schema`](OpenapiType::schema), which returns an [`OpenapiSchema`]. This assembles the static
type information in a way that is convenient to use for a generated OpenAPI specification, but
can also be utilized in other use cases as well.
# Custom Types
To gain access to the static type information of your custom types at runtime, the easiest way
is to use the derive macro:
```rust
# use openapi_type::OpenapiType;
#[derive(OpenapiType)]
struct FooBar {
foo: String,
bar: u64
}
# let schema = FooBar::schema().into_schema();
# let schema_json = serde_json::to_value(&schema).unwrap();
# assert_eq!(schema_json, serde_json::json!({
# "type": "object",
# "title": "FooBar",
# "properties": {
# "foo": {
# "type": "string"
# },
# "bar": {
# "type": "integer",
# "format": "int64",
# "minimum": 0
# }
# },
# "required": ["foo", "bar"]
# }));
```
# OpenAPI specification
Using above type, running `FooBar::schema().into_schema()` yields
```yaml
type: object
title: FooBar
properties:
foo:
type: string
bar:
type: integer
format: int64
minimum: 0
required:
- foo
- bar
```
Note, however, that this is not sufficient for more complex types. If one of your structs fields
is a type that has a name (that is, `Type::schema().name` is not `None`), above schema will contain
a reference to that schema. Therefore, always remember to put the
[`dependencies`](OpenapiSchema::dependencies) into the specification alongside the type you are
interested in.
"##]
pub use indexmap;
pub use openapi_type_derive::OpenapiType;
pub use openapiv3 as openapi;
mod impls;
#[doc(hidden)]
pub mod private;
use indexmap::IndexMap;
use openapi::{Schema, SchemaData, SchemaKind};
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct OpenapiSchema {
pub name: Option<String>,
pub description: Option<String>,
pub nullable: bool,
pub schema: SchemaKind,
pub dependencies: IndexMap<String, OpenapiSchema>
}
impl OpenapiSchema {
pub fn new(schema: SchemaKind) -> Self {
Self {
name: None,
description: None,
nullable: false,
schema,
dependencies: IndexMap::new()
}
}
pub fn into_schema(self) -> Schema {
Schema {
schema_data: SchemaData {
nullable: self.nullable,
title: self.name,
description: self.description,
..Default::default()
},
schema_kind: self.schema
}
}
}
pub trait OpenapiType {
fn schema() -> OpenapiSchema;
}
impl<'a, T: ?Sized + OpenapiType> OpenapiType for &'a T {
fn schema() -> OpenapiSchema {
T::schema()
}
}