Skip to main content

a3s_boot/routing/route/
openapi.rs

1use super::definition::RouteDefinition;
2#[cfg(feature = "openapi-schemas")]
3use crate::{openapi_schema_name, BootError, Result};
4use crate::{
5    OpenApiParameter, OpenApiRequestBody, OpenApiResponse, OpenApiRouteMetadata, OpenApiSchema,
6    OpenApiSecurityRequirement,
7};
8
9impl RouteDefinition {
10    pub fn with_openapi(mut self, metadata: OpenApiRouteMetadata) -> Self {
11        self.openapi = metadata;
12        self
13    }
14
15    pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
16        let tag = tag.into();
17        if !self.openapi.tags.contains(&tag) {
18            self.openapi.tags.push(tag);
19        }
20        self
21    }
22
23    pub fn with_operation_id(mut self, operation_id: impl Into<String>) -> Self {
24        self.openapi.operation_id = Some(operation_id.into());
25        self
26    }
27
28    pub fn with_summary(mut self, summary: impl Into<String>) -> Self {
29        self.openapi.summary = Some(summary.into());
30        self
31    }
32
33    pub fn with_description(mut self, description: impl Into<String>) -> Self {
34        self.openapi.description = Some(description.into());
35        self
36    }
37
38    pub fn with_deprecated(mut self) -> Self {
39        self.openapi.deprecated = true;
40        self
41    }
42
43    pub fn hide_from_openapi(mut self) -> Self {
44        self.openapi.hidden = true;
45        self
46    }
47
48    pub fn with_parameter(mut self, parameter: OpenApiParameter) -> Self {
49        upsert_parameter(&mut self.openapi.parameters, parameter);
50        self
51    }
52
53    pub fn with_path_parameter(self, name: impl Into<String>, schema: OpenApiSchema) -> Self {
54        self.with_parameter(OpenApiParameter::path(name, schema))
55    }
56
57    pub fn with_query_parameter(
58        self,
59        name: impl Into<String>,
60        required: bool,
61        schema: OpenApiSchema,
62    ) -> Self {
63        self.with_parameter(OpenApiParameter::query(name, required, schema))
64    }
65
66    pub fn with_header_parameter(
67        self,
68        name: impl Into<String>,
69        required: bool,
70        schema: OpenApiSchema,
71    ) -> Self {
72        self.with_parameter(OpenApiParameter::header(name, required, schema))
73    }
74
75    pub fn with_request_body(mut self, request_body: OpenApiRequestBody) -> Self {
76        self.openapi.request_body = Some(request_body);
77        self
78    }
79
80    pub fn with_json_request_body(self, schema: OpenApiSchema) -> Self {
81        self.with_request_body(OpenApiRequestBody::json(schema))
82    }
83
84    pub fn with_response(mut self, status: u16, response: OpenApiResponse) -> Self {
85        self.openapi.responses.insert(status.to_string(), response);
86        self
87    }
88
89    pub fn with_default_response(mut self, response: OpenApiResponse) -> Self {
90        self.openapi
91            .responses
92            .insert("default".to_string(), response);
93        self
94    }
95
96    pub fn with_json_response(
97        self,
98        status: u16,
99        description: impl Into<String>,
100        schema: OpenApiSchema,
101    ) -> Self {
102        self.with_response(status, OpenApiResponse::json(description, schema))
103    }
104
105    pub fn with_security_requirement(mut self, requirement: OpenApiSecurityRequirement) -> Self {
106        self.openapi.security.push(requirement);
107        self
108    }
109
110    pub fn with_bearer_auth(self) -> Self {
111        let mut requirement = OpenApiSecurityRequirement::new();
112        requirement.insert("bearerAuth".to_string(), Vec::new());
113        self.with_security_requirement(requirement)
114    }
115
116    pub fn with_schema_component(mut self, name: impl Into<String>, schema: OpenApiSchema) -> Self {
117        self.openapi.schema_components.insert(name.into(), schema);
118        self
119    }
120
121    #[cfg(feature = "openapi-schemas")]
122    pub fn try_with_json_schema_component<T>(self) -> Result<Self>
123    where
124        T: schemars::JsonSchema,
125    {
126        let schema = OpenApiSchema::json_schema::<T>()
127            .map_err(|error| BootError::Internal(error.to_string()))?;
128        Ok(self.with_schema_component(openapi_schema_name::<T>(), schema))
129    }
130}
131
132fn upsert_parameter(parameters: &mut Vec<OpenApiParameter>, parameter: OpenApiParameter) {
133    if let Some(existing) = parameters
134        .iter_mut()
135        .find(|existing| existing.location == parameter.location && existing.name == parameter.name)
136    {
137        *existing = parameter;
138        return;
139    }
140
141    parameters.push(parameter);
142}