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

#[debug_handler] doesn't improve error message for WithRejection #1337

Open
davidpdrsn opened this issue Aug 29, 2022 · 3 comments
Open

#[debug_handler] doesn't improve error message for WithRejection #1337

davidpdrsn opened this issue Aug 29, 2022 · 3 comments
Labels
A-axum-macros C-bug Category: This is a bug. E-medium Call for participation: Experience needed to fix: Medium / intermediate

Comments

@davidpdrsn
Copy link
Member

WithRejection<T, E> requires E to implement IntoResponse. If you forget that you get the familiar "handler not implemented" error and #[debug_handler] doesn't help:

use axum::extract::rejection::JsonRejection;
use axum::response::{IntoResponse, Response};
use axum::routing::{post, MethodRouter};
use axum::Json;
use axum_extra::extract::WithRejection;

#[tokio::main]
async fn main() {
    let _: MethodRouter = post(send);
}

#[axum_macros::debug_handler]
pub async fn send(
    _: WithRejection<Json<MessageSend>, ApiError>,
) -> Json<MessageSendResponse> {
    Json(MessageSendResponse { id: "".to_string() })
}

#[derive(serde::Deserialize)]
pub struct MessageSend {
    pub contents: String,
}

#[derive(serde::Serialize)]
pub struct MessageSendResponse {
    pub id: String,
}

#[derive(Debug, thiserror::Error)]
pub enum ApiError {
    #[error(transparent)]
    JsonExtractorRejection(#[from] JsonRejection),
}

// no `impl IntoResponse for ApiError`

The error message is

error[E0277]: the trait bound `fn(WithRejection<Json<MessageSend>, ApiError>) -> impl Future<Output = Json<MessageSendResponse>> {send}: Handler<_, _, _>` is not satisfied
   --> src/main.rs:9:32
    |
9   |     let _: MethodRouter = post(send);
    |                           ---- ^^^^ the trait `Handler<_, _, _>` is not implemented for `fn(WithRejection<Json<MessageSend>, ApiError>) -> impl Future<Output = Json<MessageSendResponse>> {send}`
    |                           |
    |                           required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S, B>`:
              <IntoHandler<H, T, S, B> as Handler<T, S, B>>
              <Layered<L, H, T, S, B> as Handler<T, S, B>>
              <Or<L, R, Lt, Rt, S, B> as Handler<(M, Lt, Rt), S, B>>
note: required by a bound in `post`
   --> /Users/davidpdrsn/.cargo/registry/src/github.com-1ecc6299db9ec823/axum-0.6.0-rc.1/src/routing/method_routing.rs:404:1
    |
404 | top_level_handler_fn!(post, POST);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `post`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `WithRejection<Json<MessageSend>, ApiError>: FromRequest<(), Body, _>` is not satisfied
  --> src/main.rs:14:8
   |
14 |     _: WithRejection<Json<MessageSend>, ApiError>,
   |        ^^^^^^^^^^^^^ the trait `FromRequest<(), Body, _>` is not implemented for `WithRejection<Json<MessageSend>, ApiError>`
   |
   = help: the trait `FromRequest<S, B>` is implemented for `WithRejection<E, R>`
note: required by a bound in `__axum_macros_check_send_0_from_request_check`

The generate code is

#[allow(warnings)]
fn __axum_macros_check_send_0_from_request_check<M>()
where
    WithRejection<Json<MessageSend>, ApiError>:
        ::axum::extract::FromRequest<(), axum::body::Body, M> + Send,
{
}

#[allow(warnings)]
fn __axum_macros_check_send_0_from_request_call_check() {
    __axum_macros_check_send_0_from_request_check();
}

For some reason the additional M type parameter changes rust's error message. If you remove that and instead generate

#[allow(warnings)]
fn __axum_macros_check_send_0_from_request_check()
where
    WithRejection<Json<MessageSend>, ApiError>:
        ::axum::extract::FromRequest<(), axum::body::Body> + Send,
{
}

The error message becomes

error[E0277]: the trait bound `ApiError: IntoResponse` is not satisfied
  --> src/main.rs:36:5
   |
36 | /     WithRejection<Json<MessageSend>, ApiError>:
37 | |         ::axum::extract::FromRequest<(), axum::body::Body> + Send,
   | |_________________________________________________________________^ the trait `IntoResponse` is not implemented for `ApiError`
   |

We could look into this and see if its possible to improve this.

@davidpdrsn davidpdrsn added C-bug Category: This is a bug. A-axum-macros labels Aug 29, 2022
@jplatte
Copy link
Member

jplatte commented Aug 31, 2022

For some reason the additional M type parameter changes rust's error message. If you remove that and instead generate

I think this is because WithRejection implements FromRequest for two different values of M, once directly, and once through FromRequests blanket impl. If rustc knows which one of the two is wanted, it elaborates on why it doesn't apply. If rustc doesn't know, it doesn't elaborate, presumably because it could lead to an explosion of further elaborations, rather than just a chain.

@davidpdrsn
Copy link
Member Author

I thinking we could just build in special support for WithRejection, similarly to what we for Path. If we cannot find a good general solution.

@jplatte jplatte added E-medium Call for participation: Experience needed to fix: Medium / intermediate and removed E-medium Call for participation: Experience needed to fix: Medium / intermediate labels Sep 22, 2022
@jplatte
Copy link
Member

jplatte commented Sep 22, 2022

Right, so I think what we can do is to "split out" the assertions for WithRejection (and other generic extractors that wrap another extractor). I.e. instead of the current

WithRejection<Json<MessageSend>, ApiError>: FromRequest<(), axum::body::Body> + Send,

we can generate

Json<MessageSend>: ::axum::extract::FromRequest<(), axum::body::Body> + Send,
ApiError:
    From<<Json<MessageSend> as FromRequest<(), axum::body::Body>::Rejection> + IntoResponse,

@jplatte jplatte added the E-medium Call for participation: Experience needed to fix: Medium / intermediate label Sep 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-axum-macros C-bug Category: This is a bug. E-medium Call for participation: Experience needed to fix: Medium / intermediate
Projects
None yet
Development

No branches or pull requests

2 participants