Skip to content

Conversation

@shiftcontrol-dan
Copy link
Contributor

Summary

This PR adds optional schemars::JsonSchema derives to key public structs in the propelauth crate, gated behind feature flags. This lets downstream users:

  • Return these types directly from web handlers (e.g., Axum) without creating parallel “doc-friendly” structs.
  • Generate accurate OpenAPI/JSON Schema via libraries like aide and utoipa without duplicating or regenerating models.

When the feature is disabled (default), there is no behavior change and no additional dependency is pulled in.

Motivation

Today, users who want to expose propelauth models (e.g., API key validation responses, user/org metadata) as handler return types and include them in API docs typically must:

  • Regenerate or mirror the structs locally just to add JsonSchema derives; or
  • Maintain conversion layers into separate “OpenAPI types.”

This is unnecessary duplication and a frequent source of drift and maintenance burden. These models already derive Serialize/Deserialize and are good candidates for generating schemas. By making JsonSchema available behind optional features, users can:

  • Use the upstream types directly in endpoints and docs, avoiding redefinition.
  • Keep their docs in sync with real response types automatically.

This is especially useful for endpoints managing API keys, users, and organizations where correctness and alignment are critical.

What’s changed

  • Added conditional derives to public response models, e.g.:
    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
    #[cfg_attr(any(feature = "schemars09", feature = "schemars1"), derive(JsonSchema))]
    pub struct ValidateApiKeyResponse {
        pub metadata: Option<serde_json::Value>,
        pub user: Option<UserMetadata>,
        pub org: Option<OrgMetadata>,
        pub user_in_org: Option<UserInOrg>,
        pub user_id: Option<String>,
        pub org_id: Option<String>,
    }
    The same pattern is applied to related models like ValidatePersonalApiKeyResponse, ValidateOrgApiKeyResponse, and OrgMetadata.
  • No field or serialization changes; only additive derives behind feature flags.

Feature flags and versions

  • schemars09: enables derives using schemars 0.9 API.
  • schemars1: enables derives for the latest compatible schemars (forward-friendly).

Only one should be enabled at a time. There is no default feature change.

Suggested downstream usage:

[dependencies]
propelauth = { version = "x.y", features = ["schemars09"] }
schemars = "0.9"

Or forward-looking:

[dependencies]
propelauth = { version = "x.y", features = ["schemars1] }
schemars = "~1.0" # match the latest version 1 supported

Compatibility

  • Semver: Non-breaking; derives are additive and opt-in.
  • MSRV: Unchanged; schemars is optional.
  • Runtime behavior: Unchanged.
  • Public API: Structs gain a conditional derive only when feature is enabled.

Testing and validation

  • Build matrix validation:
    • --features schemars09
    • --features schemars1
  • Manually verified schema generation in a minimal Axum + aide example referencing several models.
  • Confirmed no extra trait bounds leak when features are disabled.

Alternatives considered

  • Duplicating types downstream with JsonSchema derives: rejected due to duplication, drift, and maintenance cost.
  • Separate “openapi-models” crate: heavier maintenance, fragmentation, and version sync overhead.

Performance and size impact

  • Zero impact when features are off.
  • When enabled, derives only affect compile-time metadata; no runtime overhead.

Security

  • No changes to validation or authentication logic; schema metadata only.

Checklist

  • Feature-gated derives added to relevant public models
  • Builds with no features
  • Builds with schemars09
  • Builds with schemars1
  • Minimal aide/utoipa usage validated

Thanks for considering this! This should remove the need for users to regenerate or duplicate structs just to return them from endpoints and include them in API docs, keeping implementations and documentation in lockstep.

…` for models and parameters. Update `Cargo.toml` to include dependencies for `schemars09` and `schemars-latest`.
…th `schemars09` and `schemars-latest`. Update all relevant models and APIs.
@shiftcontrol-dan
Copy link
Contributor Author

@mrmauer let me know if you have any questions. This should be non-breaking and non-controversial :)

@mrmauer
Copy link
Contributor

mrmauer commented Aug 28, 2025

Thanks for the PR, @shiftcontrol-dan! Especially with the great, detailed breakdown of all steps/tests/etc. We'll take a deeper look and circle back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants