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
#![warn(missing_debug_implementations, rust_2018_idioms)]
#![deny(rustdoc::broken_intra_doc_links)]
#![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 other commonly used libraries `chrono`, `indexmap`, `linked-hash-map`, `time` and
`uuid` when the according feature is enabled. 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();
# let schema_json = serde_json::to_value(&schema.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;

mod impls;
mod visitor;

pub use visitor::{AlternativesVisitor, ObjectVisitor, OpenapiSchema, OpenapiVisitor, Visitor};

/// This trait needs to be implemented by every type that is being used in the OpenAPI Spec. It gives
/// access to the [OpenapiSchema] of this type. It is provided for primitive types, String and the
/// like. For use on your own types, there is a derive macro:
///
/// ```
/// # #[macro_use] extern crate openapi_type_derive;
/// #
/// #[derive(OpenapiType)]
/// struct MyResponse {
/// 	message: String
/// }
/// ```
pub trait OpenapiType {
	fn visit_type<V: Visitor>(visitor: &mut V);

	fn schema() -> OpenapiSchema {
		let mut visitor = OpenapiVisitor::new();
		Self::visit_type(&mut visitor);
		visitor
			.into_schema()
			.expect("The OpenapiType implementation failed to call the visitor")
	}
}

impl<'a, T: ?Sized + OpenapiType> OpenapiType for &'a T {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		T::visit_type(visitor)
	}
}