poem_openapi/registry/
ser.rs1use std::collections::BTreeMap;
2
3use serde::{Serialize, Serializer, ser::SerializeMap};
4
5use crate::registry::{
6 MetaApi, MetaExternalDocument, MetaInfo, MetaPath, MetaResponses, MetaSchema, MetaSchemaRef,
7 MetaSecurityScheme, MetaServer, MetaWebhook, Registry,
8};
9
10const OPENAPI_VERSION: &str = "3.0.0";
11
12impl Serialize for MetaSchemaRef {
13 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
14 match self {
15 MetaSchemaRef::Inline(schema) => schema.serialize(serializer),
16 MetaSchemaRef::Reference(name) => {
17 let mut s = serializer.serialize_map(None)?;
18 s.serialize_entry("$ref", &format!("#/components/schemas/{name}"))?;
19 s.end()
20 }
21 }
22 }
23}
24
25struct PathMap<'a>(&'a [MetaApi], Option<&'a str>);
26
27impl Serialize for PathMap<'_> {
28 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
29 let mut s = serializer.serialize_map(Some(self.0.len()))?;
30 for api in self.0 {
31 for path in &api.paths {
32 match self.1 {
33 Some(p) => s.serialize_entry(&format!("{}{}", p, path.path), path)?,
34 None => s.serialize_entry(&path.path, path)?,
35 }
36 }
37 }
38 s.end()
39 }
40}
41
42impl Serialize for MetaPath {
43 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
44 let mut s = serializer.serialize_map(None)?;
45
46 for operation in &self.operations {
47 s.serialize_entry(&operation.method.to_string().to_lowercase(), operation)?;
48 }
49
50 s.end()
51 }
52}
53
54impl Serialize for MetaResponses {
55 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
56 let mut s = serializer.serialize_map(None)?;
57 for resp in &self.responses {
58 match resp.status {
59 Some(status) => s.serialize_entry(&format!("{status}"), resp)?,
60 None => match &resp.status_range {
61 Some(status_range) => s.serialize_entry(status_range, resp)?,
62 None => s.serialize_entry("default", resp)?,
63 },
64 }
65 }
66 s.end()
67 }
68}
69
70struct WebhookMap<'a>(&'a [MetaWebhook]);
71
72impl Serialize for WebhookMap<'_> {
73 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
74 let mut s = serializer.serialize_map(Some(self.0.len()))?;
75 for webhook in self.0 {
76 let mut inner_map = BTreeMap::new();
77 inner_map.insert(
78 webhook.operation.method.to_string().to_lowercase(),
79 &webhook.operation,
80 );
81 s.serialize_entry(&webhook.name, &inner_map)?;
82 }
83 s.end()
84 }
85}
86
87pub(crate) struct Document<'a> {
88 pub(crate) info: &'a MetaInfo,
89 pub(crate) servers: &'a [MetaServer],
90 pub(crate) apis: Vec<MetaApi>,
91 pub(crate) webhooks: Vec<MetaWebhook>,
92 pub(crate) registry: Registry,
93 pub(crate) external_document: Option<&'a MetaExternalDocument>,
94 pub(crate) url_prefix: Option<&'a str>,
95}
96
97impl Serialize for Document<'_> {
98 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
99 #[derive(Serialize)]
100 #[serde(rename_all = "camelCase")]
101 struct Components<'a> {
102 schemas: &'a BTreeMap<String, MetaSchema>,
103 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
104 security_schemes: &'a BTreeMap<&'static str, MetaSecurityScheme>,
105 }
106
107 let mut s = serializer.serialize_map(None)?;
108
109 s.serialize_entry("openapi", OPENAPI_VERSION)?;
110 s.serialize_entry("info", &self.info)?;
111 s.serialize_entry("servers", self.servers)?;
112 s.serialize_entry("tags", &self.registry.tags)?;
113 if !self.webhooks.is_empty() {
114 s.serialize_entry("webhooks", &WebhookMap(&self.webhooks))?;
115 }
116 s.serialize_entry("paths", &PathMap(&self.apis, self.url_prefix))?;
117 s.serialize_entry(
118 "components",
119 &Components {
120 schemas: &self.registry.schemas,
121 security_schemes: &self.registry.security_schemes,
122 },
123 )?;
124
125 if let Some(external_document) = self.external_document {
126 s.serialize_entry("externalDocs", &external_document)?;
127 }
128
129 s.end()
130 }
131}