Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameters as struct implementing IntoParams for warp (and other frameworks) #150

Merged
merged 28 commits into from
Jun 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0a8d742
Support accepting `params(Type)` for `path` where `Type` implements
kellpossible May 30, 2022
dd6c9a6
Add a unit test for IntoParams used with the `path` macro's `params()`
kellpossible May 30, 2022
e7d8fa6
Reduce scope of unit test
kellpossible May 30, 2022
a5a4401
Implement #151 style container attribute for IntoParams
kellpossible May 31, 2022
314dd04
Add parameter_in to the IntoParams container attribute
kellpossible May 31, 2022
0362265
Updated documentation for IntoParams derive macro
kellpossible May 31, 2022
e7fe5bc
Updated `param()` macro for IntoParams derive with ParameterIn parsing
kellpossible May 31, 2022
d0b4755
Updated path and IntoParams documentation
kellpossible May 31, 2022
251634b
Allow both struct ident and list of parameters to be defined (fixes
kellpossible Jun 2, 2022
42902cd
Updated documentation for Params
kellpossible Jun 2, 2022
8d30f12
Fixes after rebase from upstream/master
kellpossible Jun 15, 2022
1738cee
Fix failing doctests
kellpossible Jun 15, 2022
df5f5ae
Remove duplicate Cargo.toml key asser-json-diff
kellpossible Jun 16, 2022
975c8c9
Remove todos and improve error handling
kellpossible Jun 16, 2022
6f989e0
Fix bug with names not being parsed from container attribute
kellpossible Jun 16, 2022
3a34e38
Allow params to be specified using both struct and bracket style
kellpossible Jun 16, 2022
13c7912
Updated path macro documentation
kellpossible Jun 16, 2022
b0b4e42
Make the struct param use ExprPath instead of Ident to support paths to
kellpossible Jun 16, 2022
9033a64
Fix failing tests for utoipa-gen
kellpossible Jun 16, 2022
cc099bf
Fix compile error for todo-warp project
kellpossible Jun 16, 2022
9cb66d9
Fix typo in docs in utoipa-gen/src/lib.rs
kellpossible Jun 17, 2022
0635e9f
Fix typo in docs in utoipa-gen/src/lib.rs
kellpossible Jun 17, 2022
e1e6b40
Fix typo in docs in utoipa-gen/src/lib.rs
kellpossible Jun 17, 2022
8b9b9c1
Remove unused Result from path.rs
kellpossible Jun 17, 2022
4f9b1ab
Update documentation for IntoParams now that ParameterIn trait has been
kellpossible Jun 17, 2022
c85b06b
Clean up attribute parsing logic to use `syn::Punctuated`
kellpossible Jun 17, 2022
451ca01
Refactor ParameterIn for manual parameter definitions to use the same
kellpossible Jun 17, 2022
ce2359c
Updated documentation for IntoParams derive
kellpossible Jun 18, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ serde_yaml = { version = "0.8", optional = true }
utoipa-gen = { version = "1.1.0", path = "./utoipa-gen" }

[dev-dependencies]
assert-json-diff = "2"
actix-web = { version = "4" }
assert-json-diff = "2"
paste = "1"
chrono = { version = "0.4", features = ["serde"] }
rust_decimal = "1"
Expand Down
33 changes: 29 additions & 4 deletions examples/todo-warp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ async fn serve_swagger(
config: Arc<Config<'static>>,
) -> Result<Box<dyn Reply + 'static>, Rejection> {
if full_path.as_str() == "/swagger-ui" {
return Ok(Box::new(warp::redirect::found(Uri::from_static("/swagger-ui/"))));
return Ok(Box::new(warp::redirect::found(Uri::from_static(
"/swagger-ui/",
))));
}

let path = tail.as_str();
Expand Down Expand Up @@ -94,7 +96,7 @@ mod todo {
};

use serde::{Deserialize, Serialize};
use utoipa::Component;
use utoipa::{Component, IntoParams};
use warp::{hyper::StatusCode, Filter, Reply};

pub type Store = Arc<Mutex<Vec<Todo>>>;
Expand All @@ -110,13 +112,22 @@ mod todo {
value: String,
}

#[derive(Debug, Deserialize, IntoParams)]
#[into_params(parameter_in = Query)]
pub struct ListQueryParams {
/// Filters the returned `Todo` items according to whether they contain the specified string.
#[param(style = Form, example = json!("task"))]
contains: Option<String>,
}

pub fn handlers() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
let store = Store::default();

let list = warp::path("todo")
.and(warp::get())
.and(warp::path::end())
.and(with_store(store.clone()))
.and(warp::query::<ListQueryParams>())
.and_then(list_todos);

let create = warp::path("todo")
Expand Down Expand Up @@ -146,14 +157,28 @@ mod todo {
#[utoipa::path(
get,
path = "/todo",
params(ListQueryParams),
responses(
(status = 200, description = "List todos successfully", body = [Todo])
)
)]
pub async fn list_todos(store: Store) -> Result<impl Reply, Infallible> {
pub async fn list_todos(
store: Store,
query: ListQueryParams,
) -> Result<impl Reply, Infallible> {
let todos = store.lock().unwrap();

Ok(warp::reply::json(&todos.clone()))
let todos: Vec<Todo> = if let Some(contains) = query.contains {
todos
.iter()
.filter(|todo| todo.value.contains(&contains))
.cloned()
.collect()
} else {
todos.clone()
};

Ok(warp::reply::json(&todos))
}

/// Create new todo item.
Expand Down
19 changes: 10 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
//! (status = 404, description = "Pet was not found")
//! ),
//! params(
//! ("id" = u64, path, description = "Pet database id to get Pet for"),
//! ("id" = u64, Path, description = "Pet database id to get Pet for"),
//! )
//! )]
//! async fn get_pet_by_id(pet_id: u64) -> Pet {
Expand Down Expand Up @@ -159,7 +159,7 @@
//! # (status = 404, description = "Pet was not found")
//! # ),
//! # params(
//! # ("id" = u64, path, description = "Pet database id to get Pet for"),
//! # ("id" = u64, Path, description = "Pet database id to get Pet for"),
//! # )
//! # )]
//! # async fn get_pet_by_id(pet_id: u64) -> Pet {
Expand Down Expand Up @@ -344,7 +344,7 @@ pub trait Component {
/// (status = 404, description = "Pet was not found")
/// ),
/// params(
/// ("id" = u64, path, description = "Pet database id to get Pet for"),
/// ("id" = u64, Path, description = "Pet database id to get Pet for"),
/// )
/// )]
/// async fn get_pet_by_id(pet_id: u64) -> Pet {
Expand Down Expand Up @@ -472,7 +472,7 @@ pub trait Modify {
fn modify(&self, openapi: &mut openapi::OpenApi);
}

/// Trait used to convert implementing type to OpenAPI parameters for **actix-web** framework.
/// Trait used to convert implementing type to OpenAPI parameters.
///
/// This trait is [derivable][derive] for structs which are used to describe `path` or `query` parameters.
/// For more details of `#[derive(IntoParams)]` refer to [derive documentation][derive].
Expand All @@ -482,7 +482,7 @@ pub trait Modify {
/// Derive [`IntoParams`] implementation. This example will fail to compile because [`IntoParams`] cannot
/// be used alone and it need to be used together with endpoint using the params as well. See
/// [derive documentation][derive] for more details.
/// ```compile_fail
/// ```
/// use utoipa::{IntoParams};
///
/// #[derive(IntoParams)]
Expand All @@ -503,12 +503,14 @@ pub trait Modify {
/// # name: String,
/// # }
/// impl utoipa::IntoParams for PetParams {
/// fn into_params() -> Vec<utoipa::openapi::path::Parameter> {
/// fn into_params(
/// parameter_in_provider: impl Fn() -> Option<utoipa::openapi::path::ParameterIn>
/// ) -> Vec<utoipa::openapi::path::Parameter> {
/// vec![
/// utoipa::openapi::path::ParameterBuilder::new()
/// .name("id")
/// .required(utoipa::openapi::Required::True)
/// .parameter_in(utoipa::openapi::path::ParameterIn::Path)
/// .parameter_in(parameter_in_provider().unwrap_or_default())
/// .description(Some("Id of pet"))
/// .schema(Some(
/// utoipa::openapi::PropertyBuilder::new()
Expand All @@ -519,7 +521,7 @@ pub trait Modify {
/// utoipa::openapi::path::ParameterBuilder::new()
/// .name("name")
/// .required(utoipa::openapi::Required::True)
/// .parameter_in(utoipa::openapi::path::ParameterIn::Path)
/// .parameter_in(parameter_in_provider().unwrap_or_default())
/// .description(Some("Name of pet"))
/// .schema(Some(
/// utoipa::openapi::PropertyBuilder::new()
Expand All @@ -531,7 +533,6 @@ pub trait Modify {
/// }
/// ```
/// [derive]: derive.IntoParams.html
#[cfg(feature = "actix_extras")]
pub trait IntoParams {
/// Provide [`Vec`] of [`openapi::path::Parameter`]s to caller. The result is used in `utoipa-gen` library to
/// provide OpenAPI parameter information for the endpoint using the parameters.
Expand Down
90 changes: 89 additions & 1 deletion tests/path_derive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![cfg(feature = "serde_json")]
use assert_json_diff::assert_json_eq;
use paste::paste;
use serde_json::{json, Value};
use utoipa::IntoParams;

mod common;

Expand Down Expand Up @@ -157,7 +160,7 @@ fn derive_path_with_defaults_success() {
),
params(
("id" = u64, description = "Foo database id"),
("since" = Option<String>, query, description = "Datetime since foo is updated")
("since" = Option<String>, Query, description = "Datetime since foo is updated")
)
)]
#[allow(unused)]
Expand Down Expand Up @@ -231,6 +234,91 @@ fn derive_path_with_security_requirements() {
}
}

#[test]
fn derive_path_params_intoparams() {
#[derive(serde::Deserialize, IntoParams)]
#[into_params(style = Form, parameter_in = Query)]
struct MyParams {
/// Foo database id.
#[param(example = 1)]
#[allow(unused)]
id: u64,
/// Datetime since foo is updated.
#[param(example = "2020-04-12T10:23:00Z")]
#[allow(unused)]
since: Option<String>,
}

#[utoipa::path(
get,
path = "/list/{id}",
responses(
(status = 200, description = "success response")
),
params(
MyParams,
("id" = i64, Path, description = "Id of some items to list")
)
)]
#[allow(unused)]
fn list(id: i64, params: MyParams) -> String {
"".to_string()
}

use utoipa::OpenApi;
#[derive(OpenApi, Default)]
#[openapi(handlers(list))]
struct ApiDoc;

let operation: Value = test_api_fn_doc! {
list,
operation: get,
path: "/list/{id}"
};

let parameters = operation.get("parameters").unwrap();

assert_json_eq!(
parameters,
json!([
{
"description": "Foo database id.",
"example": 1,
"in": "query",
"name": "id",
"required": true,
"schema": {
"format": "int64",
"type": "integer"
},
"style": "form"
},
{
"description": "Datetime since foo is updated.",
"example": "2020-04-12T10:23:00Z",
"in": "query",
"name": "since",
"required": false,
"schema": {
"type": "string"
},
"style": "form"
},
{
"deprecated": false,
"description": "Id of some items to list",
"in": "path",
"name": "id",
"required": true,
"schema": {
"format": "int64",
"type": "integer"
}
}
])
)
}

#[cfg(feature = "uuid")]
#[test]
fn derive_path_with_uuid() {
Expand Down
16 changes: 8 additions & 8 deletions tests/path_parameter_derive_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod derive_params_all_options {
(status = 200, description = "success"),
),
params(
("id" = i32, path, deprecated, description = "Search foos by ids"),
("id" = i32, Path, deprecated, description = "Search foos by ids"),
)
)]
#[allow(unused)]
Expand Down Expand Up @@ -148,11 +148,11 @@ mod mod_derive_parameters_all_types {
(status = 200, description = "success"),
),
params(
("id" = i32, path, description = "Foo id"),
("since" = String, deprecated, query, description = "Datetime since"),
("numbers" = Option<[u64]>, query, description = "Foo numbers list"),
("token" = String, header, deprecated, description = "Token of foo"),
("cookieval" = String, cookie, deprecated, description = "Foo cookie"),
("id" = i32, Path, description = "Foo id"),
("since" = String, deprecated, Query, description = "Datetime since"),
("numbers" = Option<[u64]>, Query, description = "Foo numbers list"),
("token" = String, Header, deprecated, description = "Token of foo"),
("cookieval" = String, Cookie, deprecated, description = "Foo cookie"),
)
)]
#[allow(unused)]
Expand Down Expand Up @@ -224,7 +224,7 @@ mod derive_params_without_args {
(status = 200, description = "success"),
),
params(
("id" = i32, path, description = "Foo id"),
("id" = i32, Path, description = "Foo id"),
)
)]
#[allow(unused)]
Expand Down Expand Up @@ -263,7 +263,7 @@ fn derive_params_with_params_ext() {
(status = 200, description = "success"),
),
params(
("value" = Option<[String]>, query, description = "Foo value description", style = Form, allow_reserved, deprecated, explode)
("value" = Option<[String]>, Query, description = "Foo value description", style = Form, allow_reserved, deprecated, explode)
)
)]
#[allow(unused)]
Expand Down
Loading