From 0f025f0eccec1088292f0e48c475ca8a0f16d9ff Mon Sep 17 00:00:00 2001 From: Cristi Cobzarenco Date: Thu, 6 Feb 2025 18:52:59 +0000 Subject: [PATCH] feat(openapi): add support for server variables --- poem-openapi/src/openapi.rs | 50 ++++++++++++++++++++++++++++++-- poem-openapi/src/registry/mod.rs | 14 +++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/poem-openapi/src/openapi.rs b/poem-openapi/src/openapi.rs index bddb8f3c06..00248a08ef 100644 --- a/poem-openapi/src/openapi.rs +++ b/poem-openapi/src/openapi.rs @@ -1,5 +1,5 @@ use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, marker::PhantomData, }; @@ -14,7 +14,7 @@ use crate::{ base::UrlQuery, registry::{ Document, MetaContact, MetaExternalDocument, MetaHeader, MetaInfo, MetaLicense, - MetaOperationParam, MetaParamIn, MetaSchemaRef, MetaServer, Registry, + MetaOperationParam, MetaParamIn, MetaSchemaRef, MetaServer, MetaServerVariable, Registry, }, types::Type, OpenApi, Webhook, @@ -25,6 +25,7 @@ use crate::{ pub struct ServerObject { url: String, description: Option, + variables: BTreeMap, } impl> From for ServerObject { @@ -39,6 +40,7 @@ impl ServerObject { Self { url: url.into(), description: None, + variables: BTreeMap::new(), } } @@ -50,6 +52,49 @@ impl ServerObject { ..self } } + + /// Adds a server variable with a limited set of values. + /// + /// The variable name must be present in the server URL in curly braces. + #[must_use] + pub fn enum_variable( + mut self, + name: impl Into, + description: impl Into, + default: impl Into, + enum_values: Vec>, + ) -> Self { + self.variables.insert( + name.into(), + MetaServerVariable { + description: description.into(), + default: default.into(), + enum_values: enum_values.into_iter().map(Into::into).collect(), + }, + ); + self + } + + /// Adds a server variable that can take any value. + /// + /// The variable name must be present in the server URL in curly braces. + #[must_use] + pub fn variable( + mut self, + name: impl Into, + description: impl Into, + default: impl Into, + ) -> Self { + self.variables.insert( + name.into(), + MetaServerVariable { + description: description.into(), + default: default.into(), + enum_values: Vec::new(), + }, + ); + self + } } /// A contact information for the exposed API. @@ -298,6 +343,7 @@ impl OpenApiService { self.servers.push(MetaServer { url: server.url, description: server.description, + variables: server.variables, }); self } diff --git a/poem-openapi/src/registry/mod.rs b/poem-openapi/src/registry/mod.rs index a26f9f78e5..225dc19ca0 100644 --- a/poem-openapi/src/registry/mod.rs +++ b/poem-openapi/src/registry/mod.rs @@ -542,6 +542,20 @@ pub struct MetaServer { pub url: String, #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, + + #[serde(skip_serializing_if = "BTreeMap::is_empty")] + pub variables: BTreeMap, +} + +#[derive(Debug, Eq, PartialEq, Serialize, Clone)] +pub struct MetaServerVariable { + pub default: String, + + #[serde(skip_serializing_if = "String::is_empty")] + pub description: String, + + #[serde(rename = "enum", skip_serializing_if = "Vec::is_empty")] + pub enum_values: Vec, } #[derive(Debug, Clone, Eq, PartialEq, Serialize)]