openapi_resolver/
lib.rs

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}