Skip to content

Commit

Permalink
fix query path issue
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtbuilds committed Sep 27, 2024
1 parent a0a8191 commit 665ca4f
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 229 deletions.
24 changes: 22 additions & 2 deletions core/src/operation.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
use openapiv3::Operation;
use openapiv3::{Operation, Parameter, RefOr, Schema};

pub struct OperationRegister {
// module_path: &'static str,
pub name: &'static str,
pub constructor: &'static (dyn Sync + Send + Fn() -> Operation),
}

pub trait OaParameter {
fn body_schema() -> Option<RefOr<Schema>> {
None
}
fn parameter_schemas() -> Vec<RefOr<Schema>> {
Vec::new()
}
fn parameters() -> Vec<RefOr<Parameter>> {
Vec::new()
}
}

impl<T, E> OaParameter for Result<T, E>
where
T: OaParameter,
{
fn body_schema() -> Option<RefOr<Schema>> {
T::body_schema()
}
}

inventory::collect!(OperationRegister);
64 changes: 6 additions & 58 deletions core/src/schema.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use std::collections::HashMap;

use openapiv3 as oa;
use openapiv3::{ReferenceOr, Schema};

#[cfg(feature = "actix")]
Expand All @@ -25,18 +23,16 @@ mod bigdecimal;
mod http;
#[cfg(feature = "sid")]
mod sid;
mod tuple;

pub trait OaSchema {
fn schema() -> Schema;

fn schema_ref() -> ReferenceOr<Schema> {
ReferenceOr::Item(Self::schema())
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
Vec::new()
}

/// You should rarely if ever implement this method.
#[doc(hidden)]
fn body_schema() -> Option<ReferenceOr<Schema>> {
Some(Self::schema_ref())
}
Expand Down Expand Up @@ -78,46 +74,6 @@ macro_rules! impl_oa_schema_passthrough {
};
}

// We have to define this macro instead of defining OaSchema for tuples because
// the Path types have to implement parameters(). parameters calls out to T::schema_ref()
// because we need to implement something like Path<u64> : OaSchema,
// but tuples don't work the same way, because schema doesn't return multiple schemas.

// The alternative is a second trait interface like OaSchemaTuple, and we'd impl<T: OaSchemaTuple>
// for axum::extract::Path and friends
#[macro_export]
macro_rules! impl_parameters {
// Pattern for generic axum types with tuple generics (A1, A2, etc.)
($($path:ident)::+, $($A:ident),+) => {
impl<$($A: $crate::OaSchema),+> $crate::OaSchema for $($path)::+<($($A,)+)> {
fn schema() -> $crate::Schema {
panic!("Call parameters() for this type, not schema().");
}

fn parameters() -> Vec<$crate::ReferenceOr<$crate::Parameter>> {
vec![
$(
$crate::ReferenceOr::Item($crate::Parameter::path(stringify!($A), $A::schema_ref())),
)+
]
}

fn body_schema() -> Option<$crate::ReferenceOr<$crate::Schema>> {
None
}
}
};
}

impl OaSchema for () {
fn schema() -> Schema {
panic!("Call body_schema() for (), not schema().")
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
None
}
}

impl_oa_schema!(bool, Schema::new_bool());

Expand Down Expand Up @@ -176,20 +132,12 @@ where
}
}

impl<T, E> OaSchema for Result<T, E>
where
T: OaSchema,
{
impl OaSchema for () {
fn schema() -> Schema {
T::schema()
}

fn schema_ref() -> ReferenceOr<Schema> {
T::schema_ref()
panic!("Unit type has no schema")
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
T::body_schema()
None
}
}

Expand Down
82 changes: 31 additions & 51 deletions core/src/schema/actix.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,54 @@
use openapiv3 as oa;
use openapiv3::{ReferenceOr, Schema};
use openapiv3::{RefOr, Schema, SchemaKind, Type};

use crate::OaSchema;
use crate::{OaParameter, OaSchema};

impl<T: OaSchema> OaSchema for actix_web::web::Json<T> {
fn schema() -> Schema {
panic!("Call body_schema() for Json, not schema().")
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
impl<T: OaSchema> OaParameter for actix_web::web::Json<T> {
fn body_schema() -> Option<RefOr<Schema>> {
T::body_schema()
}
}

impl<T> OaSchema for actix_web::web::Data<T> {
fn schema() -> Schema {
panic!("Call parameters() for Data, not schema().");
}
fn body_schema() -> Option<ReferenceOr<Schema>> {
None
}
}

impl OaSchema for actix_web::HttpRequest {
fn schema() -> Schema {
panic!("Call parameters() for HttpRequest, not schema().");
}
}

impl OaSchema for actix_web::HttpResponse {
fn schema() -> Schema {
panic!("Call body_schema() for HttpResponse, not schema().");
Schema::new_any()
}
}

impl<T: OaSchema> OaSchema for actix_web::web::Path<T> {
fn schema() -> Schema {
panic!("Call parameters() for Path, not schema().");
}
impl<T> OaParameter for actix_web::web::Data<T> {}
impl OaParameter for actix_web::HttpRequest {}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
T::parameters()
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
None
impl<T: OaParameter> OaParameter for actix_web::web::Path<T> {
fn parameters() -> Vec<RefOr<oa::Parameter>> {
T::parameter_schemas()
.into_iter()
.map(|s| RefOr::Item(oa::Parameter::path("path", s)))
.collect()
}
}

impl<T: OaSchema> OaSchema for actix_web::web::Query<T> {
fn schema() -> Schema {
panic!("Call parameters() for Query, not schema().");
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
T::parameters()
}
fn body_schema() -> Option<ReferenceOr<Schema>> {
None
impl<T: OaParameter> OaParameter for actix_web::web::Query<T> {
fn parameters() -> Vec<RefOr<oa::Parameter>> {
T::parameter_schemas()
.into_iter()
.flat_map(|s| s.into_item())
.flat_map(|s| match s.kind {
SchemaKind::Type(Type::Object(o)) => { Some(o.properties) }
_ => None
})
.flatten()
.map(|(k, v)| RefOr::Item(oa::Parameter::query(k, v)))
.collect()
}
}

#[cfg(feature = "qs")]
impl<T: OaSchema> OaSchema for serde_qs::actix::QsQuery<T> {
fn schema() -> Schema {
panic!("Call parameters() for QsQuery, not schema().");
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
let p = oa::Parameter::query("query", T::schema_ref());
vec![ReferenceOr::Item(p)]
impl<T: OaParameter> OaParameter for serde_qs::actix::QsQuery<T> {
fn parameters() -> Vec<RefOr<oa::Parameter>> {
T::parameter_schemas()
.into_iter()
.map(|s| RefOr::Item(oa::Parameter::query("query", s)))
.collect()
}
}
128 changes: 37 additions & 91 deletions core/src/schema/axum.rs
Original file line number Diff line number Diff line change
@@ -1,110 +1,56 @@
use openapiv3::{ReferenceOr, Schema};
use openapiv3::{RefOr, Schema, SchemaKind, Type};
use openapiv3 as oa;

use crate::{impl_parameters, OaSchema};

impl<T: OaSchema> OaSchema for axum::extract::Json<T> {
fn schema() -> Schema {
panic!("Call body_schema() for Json, not schema().")
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
T::body_schema()
}
}

impl<T> OaSchema for axum::extract::Extension<T> {
fn schema() -> Schema {
panic!("Call parameters() for Extension, not schema().")
}
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}

impl<T> OaSchema for axum::extract::State<T> {
fn schema() -> Schema {
panic!("Call parameters() for State, not schema().")
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
None
}
}
use crate::{OaParameter, OaSchema};

impl<T> OaSchema for http::Response<T> {
fn schema() -> Schema {
Schema::new_any()
}
}

impl<T> OaSchema for http::Request<T> {
fn schema() -> Schema {
panic!("Call parameters() for Request, not schema().")
}
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}

impl<T> OaSchema for axum::extract::ConnectInfo<T> {
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
fn schema() -> Schema {
panic!("Call parameters() for ConnectInfo, not schema().")
}
}

impl OaSchema for http::HeaderMap {
fn schema() -> Schema {
panic!("Call parameters() for HeaderMap, not schema().")
impl<T: OaSchema> OaParameter for axum::extract::Json<T> {
fn body_schema() -> Option<RefOr<Schema>> {
T::body_schema()
}
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}
impl<T> OaParameter for axum::extract::Extension<T> {}
impl<T> OaParameter for axum::extract::State<T> {}
impl<T> OaParameter for http::Request<T> {}
impl<T> OaParameter for axum::extract::ConnectInfo<T> {}
impl OaParameter for http::HeaderMap {}
impl OaParameter for http::request::Parts {}

impl<T: OaSchema> OaSchema for axum::extract::Query<T> {
fn schema() -> Schema {
panic!("Call parameters() for Query, not schema().")
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
let p = oa::Parameter::query("query", T::schema_ref());
vec![ReferenceOr::Item(p)]
impl<T: OaParameter> OaParameter for axum::extract::Query<T> {
fn parameters() -> Vec<RefOr<oa::Parameter>> {
T::parameter_schemas()
.into_iter()
.flat_map(|s| s.into_item())
.flat_map(|s| match s.kind {
SchemaKind::Type(Type::Object(o)) => { Some(o.properties) }
_ => None
})
.flatten()
.map(|(k, v)| RefOr::Item(oa::Parameter::query(k, v)))
.collect()
}

fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}

impl<T: OaSchema> OaSchema for axum::extract::Path<T> {
fn schema() -> Schema {
panic!("Call parameters() for Path, not schema().");
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
let p = oa::Parameter::path("path", T::schema_ref());
vec![ReferenceOr::Item(p)]
impl<T: OaParameter> OaParameter for axum::extract::Path<T> {
fn parameters() -> Vec<RefOr<oa::Parameter>> {
T::parameter_schemas()
.into_iter()
.map(|s| RefOr::Item(oa::Parameter::path("path", s)))
.collect()
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
None
}
}

impl OaSchema for http::request::Parts {
fn schema() -> Schema {
panic!("Call parameters() for Parts, not schema().")
}
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}

#[cfg(feature = "qs")]
impl<T: OaSchema> OaSchema for serde_qs::axum::QsQuery<T> {
fn schema() -> Schema {
panic!("Call parameters() for QsQuery, not schema().")
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
let p = oa::Parameter::query("query", T::schema_ref());
vec![ReferenceOr::Item(p)]
}
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}

impl_parameters!(axum::extract::Path, A1);
impl_parameters!(axum::extract::Path, A1, A2);
impl_parameters!(axum::extract::Path, A1, A2, A3);
impl<T: OaParameter> OaParameter for serde_qs::axum::QsQuery<T> {
fn parameters() -> Vec<RefOr<oa::Parameter>> {
T::parameter_schemas()
.into_iter()
.map(|s| RefOr::Item(oa::Parameter::query("query", s)))
.collect()
}
}
Loading

0 comments on commit 665ca4f

Please sign in to comment.