Skip to content

Commit 635daba

Browse files
committed
Implement schemars::JsonSchema for non-secret new types.
Placed behind a `schemars` feature flag.
1 parent daf4db6 commit 635daba

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
[package]
22
name = "oauth2"
3-
authors = ["Alex Crichton <[email protected]>", "Florin Lipan <[email protected]>", "David A. Ramos <[email protected]>"]
3+
authors = [
4+
"Alex Crichton <[email protected]>",
5+
"Florin Lipan <[email protected]>",
6+
"David A. Ramos <[email protected]>",
7+
]
48
version = "5.0.0-alpha.4"
59
license = "MIT OR Apache-2.0"
610
description = "An extensible, strongly-typed implementation of OAuth2"
@@ -22,6 +26,7 @@ native-tls = ["reqwest/native-tls"]
2226
reqwest-blocking = ["reqwest/blocking"]
2327
rustls-tls = ["reqwest/rustls-tls"]
2428
timing-resistant-secret-traits = []
29+
schemars = ["dep:schemars"]
2530

2631
[[example]]
2732
name = "github"
@@ -61,6 +66,9 @@ url = { version = "2.1", features = ["serde"] }
6166
chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde", "std", "wasmbind"] }
6267
serde_path_to_error = "0.1.2"
6368

69+
# Feature: schemars
70+
schemars = { version = "0.8", optional = true }
71+
6472
[target.'cfg(target_arch = "wasm32")'.dependencies]
6573
getrandom = { version = "0.2", features = ["js"] }
6674

src/types.rs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ macro_rules! new_type {
7777
}
7878
) => {
7979
$(#[$attr])*
80-
#[derive(Clone, Debug, PartialEq)]
80+
#[derive(Clone, Debug, PartialEq, Eq, Hash, ::serde::Serialize, ::serde::Deserialize)]
81+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
8182
pub struct $name(
8283
$(#[$type_attr])*
8384
$type
@@ -344,13 +345,28 @@ macro_rules! new_url_type {
344345
}
345346
}
346347
impl Eq for $name {}
348+
349+
350+
#[cfg(feature = "schemars")]
351+
impl schemars::JsonSchema for $name {
352+
fn schema_name() -> String {
353+
stringify!($name).to_owned()
354+
}
355+
356+
fn schema_id() -> std::borrow::Cow<'static, str> {
357+
std::borrow::Cow::Borrowed(concat!("oauth2::", stringify!($name)))
358+
}
359+
360+
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
361+
gen.subschema_for::<String>()
362+
}
363+
}
347364
};
348365
}
349366

350367
new_type![
351368
/// Client identifier issued to the client during the registration process described by
352369
/// [Section 2.2](https://tools.ietf.org/html/rfc6749#section-2.2).
353-
#[derive(Deserialize, Serialize, Eq, Hash)]
354370
ClientId(String)
355371
];
356372

@@ -385,19 +401,16 @@ new_url_type![
385401
new_type![
386402
/// Authorization endpoint response (grant) type defined in
387403
/// [Section 3.1.1](https://tools.ietf.org/html/rfc6749#section-3.1.1).
388-
#[derive(Deserialize, Serialize, Eq, Hash)]
389404
ResponseType(String)
390405
];
391406
new_type![
392407
/// Resource owner's username used directly as an authorization grant to obtain an access
393408
/// token.
394-
#[derive(Deserialize, Serialize, Eq, Hash)]
395409
ResourceOwnerUsername(String)
396410
];
397411

398412
new_type![
399413
/// Access token scope, as defined by the authorization server.
400-
#[derive(Deserialize, Serialize, Eq, Hash)]
401414
Scope(String)
402415
];
403416
impl AsRef<str> for Scope {
@@ -409,7 +422,6 @@ impl AsRef<str> for Scope {
409422
new_type![
410423
/// Code Challenge Method used for [PKCE](https://tools.ietf.org/html/rfc7636) protection
411424
/// via the `code_challenge_method` parameter.
412-
#[derive(Deserialize, Serialize, Eq, Hash)]
413425
PkceCodeChallengeMethod(String)
414426
];
415427
// This type intentionally does not implement Clone in order to make it difficult to reuse PKCE
@@ -662,4 +674,39 @@ mod tests {
662674
"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
663675
);
664676
}
677+
678+
#[cfg(feature = "schemars")]
679+
mod json_schema {
680+
use schemars::schema_for;
681+
use serde_json::json;
682+
683+
use crate::{ClientId, RedirectUrl};
684+
685+
#[test]
686+
fn generates_new_type_json_schema() {
687+
let expected_schema = json!({
688+
"$schema": "http://json-schema.org/draft-07/schema#",
689+
"title": "ClientId",
690+
"description": "Client identifier issued to the client during the registration process described by [Section 2.2](https://tools.ietf.org/html/rfc6749#section-2.2).",
691+
"type": "string"
692+
});
693+
694+
let schema = schema_for!(ClientId);
695+
let actual_schema = serde_json::to_value(&schema).unwrap();
696+
assert_eq!(expected_schema, actual_schema)
697+
}
698+
699+
#[test]
700+
fn generates_new_url_type_json_schema() {
701+
let expected_schema = json!({
702+
"$schema": "http://json-schema.org/draft-07/schema#",
703+
"title": "RedirectUrl",
704+
"type": "string"
705+
});
706+
707+
let schema = schema_for!(RedirectUrl);
708+
let actual_schema = serde_json::to_value(&schema).unwrap();
709+
assert_eq!(expected_schema, actual_schema);
710+
}
711+
}
665712
}

0 commit comments

Comments
 (0)