mirror of
https://github.com/tokio-rs/axum.git
synced 2025-03-13 11:18:33 +01:00
Improve Path
error when its extracted multiple times (#1023)
* Improve `Path` error * Improve docs * changelog * Update axum/src/extract/path/mod.rs Co-authored-by: Jonas Platte <jplatte+git@posteo.de> * fix test Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
This commit is contained in:
parent
280334347b
commit
08cbade3cb
2 changed files with 47 additions and 10 deletions
|
@ -8,8 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
# Unreleased
|
||||
|
||||
- **added:** Add `WebSocket::protocol` to return the selected WebSocket subprotocol, if there is one. ([#1022])
|
||||
- **fixed:** Improve error for `PathRejection::WrongNumberOfParameters` to hint at using
|
||||
`Path<(String, String)>` or `Path<SomeStruct>` ([#1023])
|
||||
- **fixed:** `PathRejection::WrongNumberOfParameters` now uses `500 Internal Server Error` since
|
||||
its a programmer error and not a client error ([#1023])
|
||||
|
||||
[#1022]: https://github.com/tokio-rs/axum/pull/1022
|
||||
[#1023]: https://github.com/tokio-rs/axum/pull/1023
|
||||
|
||||
# 0.5.5 (10. May, 2022)
|
||||
|
||||
|
|
|
@ -66,8 +66,7 @@ use std::{
|
|||
/// ```
|
||||
///
|
||||
/// Path segments also can be deserialized into any type that implements
|
||||
/// [`serde::Deserialize`]. Path segment labels will be matched with struct
|
||||
/// field names.
|
||||
/// [`serde::Deserialize`]. This includes tuples and structs:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use axum::{
|
||||
|
@ -78,6 +77,7 @@ use std::{
|
|||
/// use serde::Deserialize;
|
||||
/// use uuid::Uuid;
|
||||
///
|
||||
/// // Path segment labels will be matched with struct field names
|
||||
/// #[derive(Deserialize)]
|
||||
/// struct Params {
|
||||
/// user_id: Uuid,
|
||||
|
@ -90,7 +90,17 @@ use std::{
|
|||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// let app = Router::new().route("/users/:user_id/team/:team_id", get(users_teams_show));
|
||||
/// // When using tuples the path segments will be matched by their position in the route
|
||||
/// async fn users_teams_create(
|
||||
/// Path((user_id, team_id)): Path<(String, String)>,
|
||||
/// ) {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// let app = Router::new().route(
|
||||
/// "/users/:user_id/team/:team_id",
|
||||
/// get(users_teams_show).post(users_teams_create),
|
||||
/// );
|
||||
/// # async {
|
||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
|
@ -319,11 +329,19 @@ impl fmt::Display for ErrorKind {
|
|||
match self {
|
||||
ErrorKind::Message(error) => error.fmt(f),
|
||||
ErrorKind::InvalidUtf8InPathParam { key } => write!(f, "Invalid UTF-8 in `{}`", key),
|
||||
ErrorKind::WrongNumberOfParameters { got, expected } => write!(
|
||||
f,
|
||||
"Wrong number of parameters. Expected {} but got {}",
|
||||
expected, got
|
||||
),
|
||||
ErrorKind::WrongNumberOfParameters { got, expected } => {
|
||||
write!(
|
||||
f,
|
||||
"Wrong number of path arguments for `Path`. Expected {} but got {}",
|
||||
expected, got
|
||||
)?;
|
||||
|
||||
if *expected == 1 {
|
||||
write!(f, ". Note that multiple parameters must be extracted with a tuple `Path<(_, _)>` or a struct `Path<YourParams>`")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
ErrorKind::UnsupportedType { name } => write!(f, "Unsupported type `{}`", name),
|
||||
ErrorKind::ParseErrorAtKey {
|
||||
key,
|
||||
|
@ -368,14 +386,13 @@ impl IntoResponse for FailedToDeserializePathParams {
|
|||
let (status, body) = match self.0.kind {
|
||||
ErrorKind::Message(_)
|
||||
| ErrorKind::InvalidUtf8InPathParam { .. }
|
||||
| ErrorKind::WrongNumberOfParameters { .. }
|
||||
| ErrorKind::ParseError { .. }
|
||||
| ErrorKind::ParseErrorAtIndex { .. }
|
||||
| ErrorKind::ParseErrorAtKey { .. } => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
format!("Invalid URL: {}", self.0.kind),
|
||||
),
|
||||
ErrorKind::UnsupportedType { .. } => {
|
||||
ErrorKind::WrongNumberOfParameters { .. } | ErrorKind::UnsupportedType { .. } => {
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, self.0.kind.to_string())
|
||||
}
|
||||
};
|
||||
|
@ -539,4 +556,19 @@ mod tests {
|
|||
let res = client.get("/foo%20bar").send().await;
|
||||
assert_eq!(res.text().await, "foo bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn two_path_extractors() {
|
||||
let app = Router::new().route("/:a/:b", get(|_: Path<String>, _: Path<String>| async {}));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
let res = client.get("/a/b").send().await;
|
||||
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||
assert_eq!(
|
||||
res.text().await,
|
||||
"Wrong number of path arguments for `Path`. Expected 1 but got 2. \
|
||||
Note that multiple parameters must be extracted with a tuple `Path<(_, _)>` or a struct `Path<YourParams>`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue