1use openapiv3::{
2 Header, OpenAPI, Parameter, PathItem, ReferenceOr, RequestBody, Response, Schema,
3 SecurityScheme,
4};
5
6pub fn resolve_reference<'a, T>(source: &'a ReferenceOr<T>, root: &'a OpenAPI) -> Option<&'a T>
7where
8 &'a T: RefResolve<'a>,
9{
10 match source {
11 ReferenceOr::Item(item) => Some(item),
12 ReferenceOr::Reference { reference } => RefResolve::resolve(&root, reference),
13 }
14}
15
16pub trait RefResolve<'d>: Sized {
17 fn resolve(api: &'d OpenAPI, link: &'d str) -> Option<Self>;
18}
19
20impl<'a> RefResolve<'a> for &'a Response {
21 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
22 if let Some(name) = link.strip_prefix("#/components/responses/") {
23 match &api.components {
24 Some(components) => match components.responses.get(name) {
25 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
26 Some(ReferenceOr::Item(item)) => Some(item),
27 None => None,
28 },
29 None => None,
30 }
31 } else {
32 None
33 }
34 }
35}
36
37impl<'a> RefResolve<'a> for &'a Parameter {
38 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
39 if let Some(name) = link.strip_prefix("#/components/parameters/") {
40 match &api.components {
41 Some(components) => match components.parameters.get(name) {
42 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
43 Some(ReferenceOr::Item(item)) => Some(item),
44 None => None,
45 },
46 None => None,
47 }
48 } else {
49 None
50 }
51 }
52}
53
54impl<'a> RefResolve<'a> for &'a SecurityScheme {
55 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
56 if let Some(name) = link.strip_prefix("#/components/securitySchemes/") {
57 match &api.components {
58 Some(components) => match components.security_schemes.get(name) {
59 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
60 Some(ReferenceOr::Item(item)) => Some(item),
61 None => None,
62 },
63 None => None,
64 }
65 } else {
66 None
67 }
68 }
69}
70
71impl<'a> RefResolve<'a> for &'a RequestBody {
72 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
73 if let Some(name) = link.strip_prefix("#/components/requestBodies/") {
74 match &api.components {
75 Some(components) => match components.request_bodies.get(name) {
76 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
77 Some(ReferenceOr::Item(item)) => Some(item),
78 None => None,
79 },
80 None => None,
81 }
82 } else {
83 None
84 }
85 }
86}
87
88impl<'a> RefResolve<'a> for &'a Header {
89 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
90 if let Some(name) = link.strip_prefix("#/components/headers/") {
91 match &api.components {
92 Some(components) => match components.headers.get(name) {
93 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
94 Some(ReferenceOr::Item(item)) => Some(item),
95 None => None,
96 },
97 None => None,
98 }
99 } else {
100 None
101 }
102 }
103}
104
105impl<'a> RefResolve<'a> for &'a Schema {
106 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
107 if let Some(name) = link.strip_prefix("#/components/schemas/") {
108 match &api.components {
109 Some(components) => match components.schemas.get(name) {
110 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
111 Some(ReferenceOr::Item(item)) => Some(item),
112 None => None,
113 },
114 None => None,
115 }
116 } else {
117 None
118 }
119 }
120}
121
122impl<'a> RefResolve<'a> for &'a PathItem {
123 fn resolve(api: &'a OpenAPI, link: &'a str) -> Option<Self> {
124 if let Some(name) = link.strip_prefix("#/paths/") {
125 match api.paths.get(name) {
126 Some(ReferenceOr::Reference { reference }) => Self::resolve(api, reference),
127 Some(ReferenceOr::Item(item)) => Some(item),
128 None => None,
129 }
130 } else {
131 None
132 }
133 }
134}