Skip to content

Commit

Permalink
add openapi extensions "x-tokenName" (#763)
Browse files Browse the repository at this point in the history
* add token_name to Oauth2 struct
Setting x-tokenname makes it possible to choose which token to use
* let the user choose what extension to enable
* add extensions in all places required by spec

Example of how to add extensions for oauth configuration.
```rs
 #[derive(Clone)]
 struct SecurityAddon;

 impl Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            let mut oauth = OAuth2::new([Flow::AuthorizationCode(AuthorizationCode::new(
                "https://accounts.google.com/o/oauth2/auth",
                "https://oauth2.googleapis.com/token",
                Scopes::from_iter([("email", "use your email address"), ("openid", "openid")]),
            ))]);
            oauth.extensions = Some(HashMap::from_iter([(
                "x-tokenName".to_string(),
                Value::String("id_token".to_string()),
            )]));
            components.add_security_scheme("token", SecurityScheme::OAuth2(oauth));
        }
    }
}
```
  • Loading branch information
lucasgranberg authored Oct 25, 2023
1 parent 50db1b0 commit f43efc7
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 3 deletions.
11 changes: 11 additions & 0 deletions utoipa/src/openapi/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//! [info]: <https://spec.openapis.org/oas/latest.html#info-object>
//! [openapi_trait]: ../../trait.OpenApi.html
//! [derive]: ../../derive.OpenApi.html
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use super::{builder, set_value};
Expand Down Expand Up @@ -66,6 +68,10 @@ builder! {

/// Document version typically the API version.
pub version: String,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -120,6 +126,11 @@ impl InfoBuilder {
pub fn license(mut self, license: Option<License>) -> Self {
set_value!(self license license)
}

/// Add openapi extensions (x-something) of the API.
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

builder! {
Expand Down
38 changes: 37 additions & 1 deletion utoipa/src/openapi/path.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Implements [OpenAPI Path Object][paths] types.
//!
//! [paths]: https://spec.openapis.org/oas/latest.html#paths-object
use std::iter;
use std::{collections::HashMap, iter};

use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -34,6 +34,10 @@ builder! {
/// Map of relative paths with [`PathItem`]s holding [`Operation`]s matching
/// api endpoints.
pub paths: PathsMap<String, PathItem>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -97,6 +101,11 @@ impl PathsBuilder {

self
}

/// Add extensions to the paths section.
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

builder! {
Expand Down Expand Up @@ -135,6 +144,10 @@ builder! {
/// per [`PathItemType`].
#[serde(flatten)]
pub operations: PathsMap<PathItemType, Operation>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -184,6 +197,11 @@ impl PathItemBuilder {
pub fn parameters<I: IntoIterator<Item = Parameter>>(mut self, parameters: Option<I>) -> Self {
set_value!(self parameters parameters.map(|parameters| parameters.into_iter().collect()))
}

/// Add openapi extensions (x-something) to this [`PathItem`].
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

/// Path item operation type.
Expand Down Expand Up @@ -295,6 +313,10 @@ builder! {
/// Alternative [`Server`]s for this [`Operation`].
#[serde(skip_serializing_if = "Option::is_none")]
pub servers: Option<Vec<Server>>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -436,6 +458,11 @@ impl OperationBuilder {

self
}

/// Add openapi extensions (x-something) of the [`Operation`].
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

builder! {
Expand Down Expand Up @@ -506,6 +533,10 @@ builder! {
/// within [`Parameter::schema`] if defined.
#[serde(skip_serializing_if = "Option::is_none")]
example: Option<Value>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -577,6 +608,11 @@ impl ParameterBuilder {
pub fn example(mut self, example: Option<Value>) -> Self {
set_value!(self example example)
}

/// Add openapi extensions (x-something) to the [`Parameter`].
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

/// In definition of [`Parameter`].
Expand Down
11 changes: 10 additions & 1 deletion utoipa/src/openapi/response.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Implements [OpenApi Responses][responses].
//!
//! [responses]: https://spec.openapis.org/oas/latest.html#responses-object
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};

use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -118,6 +118,10 @@ builder! {
/// will create and show default example according to the first entry in `content` map.
#[serde(skip_serializing_if = "IndexMap::is_empty", default)]
pub content: IndexMap<String, Content>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -152,6 +156,11 @@ impl ResponseBuilder {

self
}

/// Add openapi extensions (x-something) to the [`Header`].
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

impl From<ResponseBuilder> for RefOr<Response> {
Expand Down
11 changes: 10 additions & 1 deletion utoipa/src/openapi/security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
//! Refer to [`SecurityScheme`] for usage and more details.
//!
//! [security]: https://spec.openapis.org/oas/latest.html#security-scheme-object
use std::{collections::BTreeMap, iter};
use std::{
collections::{BTreeMap, HashMap},
iter,
};

use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -352,6 +355,10 @@ pub struct OAuth2 {
/// Optional description for the [`OAuth2`] [`Flow`] [`SecurityScheme`].
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}

impl OAuth2 {
Expand Down Expand Up @@ -391,6 +398,7 @@ impl OAuth2 {
.into_iter()
.map(|auth_flow| (String::from(auth_flow.get_type_as_str()), auth_flow)),
),
extensions: None,
description: None,
}
}
Expand Down Expand Up @@ -433,6 +441,7 @@ impl OAuth2 {
.into_iter()
.map(|auth_flow| (String::from(auth_flow.get_type_as_str()), auth_flow)),
),
extensions: None,
description: Some(description.into()),
}
}
Expand Down
11 changes: 11 additions & 0 deletions utoipa/src/openapi/tag.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Implements [OpenAPI Tag Object][tag] types.
//!
//! [tag]: https://spec.openapis.org/oas/latest.html#tag-object
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use super::{builder, external_docs::ExternalDocs, set_value};
Expand Down Expand Up @@ -28,6 +30,10 @@ builder! {
/// Additional external documentation for the tag.
#[serde(skip_serializing_if = "Option::is_none")]
pub external_docs: Option<ExternalDocs>,

/// Optional extensions "x-something"
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<HashMap<String, serde_json::Value>>,
}
}

Expand Down Expand Up @@ -56,4 +62,9 @@ impl TagBuilder {
pub fn external_docs(mut self, external_docs: Option<ExternalDocs>) -> Self {
set_value!(self external_docs external_docs)
}

/// Add openapi extensions (x-something) to the tag.
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
}

0 comments on commit f43efc7

Please sign in to comment.