Document not being able to mix fallible and infallible routes (#232)

I haven't been able to find a proper solution for #89 so for now I think
we should document the issue and move on with shipping 0.2.

Part of https://github.com/tokio-rs/axum/issues/89
This commit is contained in:
David Pedersen 2021-08-21 15:36:50 +02:00 committed by GitHub
parent 8a61b9ffe1
commit fbd43c6600
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 79 additions and 0 deletions

View File

@ -9,6 +9,7 @@
//! - [Precedence](#precedence) //! - [Precedence](#precedence)
//! - [Matching multiple methods](#matching-multiple-methods) //! - [Matching multiple methods](#matching-multiple-methods)
//! - [Routing to any `Service`](#routing-to-any-service) //! - [Routing to any `Service`](#routing-to-any-service)
//! - [Routing to fallible services](#routing-to-fallible-services)
//! - [Nesting routes](#nesting-routes) //! - [Nesting routes](#nesting-routes)
//! - [Extractors](#extractors) //! - [Extractors](#extractors)
//! - [Building responses](#building-responses) //! - [Building responses](#building-responses)
@ -255,6 +256,83 @@
//! Routing to arbitrary services in this way has complications for backpressure //! Routing to arbitrary services in this way has complications for backpressure
//! ([`Service::poll_ready`]). See the [`service`] module for more details. //! ([`Service::poll_ready`]). See the [`service`] module for more details.
//! //!
//! ### Routing to fallible services
//!
//! Note that routing to general services has a small gotcha when it comes to
//! errors. axum currently does not support mixing routes to fallible services
//! with infallible handlers. For example this does _not_ compile:
//!
//! ```compile_fail
//! use axum::{
//! Router,
//! service,
//! handler::get,
//! http::{Request, Response},
//! body::Body,
//! };
//! use std::io;
//! use tower::service_fn;
//!
//! let app = Router::new()
//! // this route cannot fail
//! .route("/foo", get(|| async {}))
//! // this route can fail with io::Error
//! .route(
//! "/",
//! service::get(service_fn(|_req: Request<Body>| async {
//! let contents = tokio::fs::read_to_string("some_file").await?;
//! Ok::<_, io::Error>(Response::new(Body::from(contents)))
//! })),
//! );
//! # async {
//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
//! # };
//! ```
//!
//! The solution is to use [`handle_error`] and handle the error from the
//! service:
//!
//! ```
//! use axum::{
//! Router,
//! service,
//! handler::get,
//! http::{Request, Response},
//! response::IntoResponse,
//! body::Body,
//! };
//! use std::{io, convert::Infallible};
//! use tower::service_fn;
//!
//! let app = Router::new()
//! // this route cannot fail
//! .route("/foo", get(|| async {}))
//! // this route can fail with io::Error
//! .route(
//! "/",
//! service::get(service_fn(|_req: Request<Body>| async {
//! let contents = tokio::fs::read_to_string("some_file").await?;
//! Ok::<_, io::Error>(Response::new(Body::from(contents)))
//! }))
//! .handle_error(handle_io_error),
//! );
//!
//! fn handle_io_error(error: io::Error) -> Result<impl IntoResponse, Infallible> {
//! # Ok(())
//! // ...
//! }
//! # async {
//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
//! # };
//! ```
//!
//! In this particular case you can also handle the error directly in
//! `service_fn` but that is not possible, if you're routing to a service which
//! you don't control.
//!
//! See ["Error handling"](#error-handling) for more details on [`handle_error`]
//! and error handling in general.
//!
//! ## Nesting routes //! ## Nesting routes
//! //!
//! Routes can be nested by calling [`Router::nest`](routing::Router::nest): //! Routes can be nested by calling [`Router::nest`](routing::Router::nest):
@ -762,6 +840,7 @@
//! [`OriginalUri`]: crate::extract::OriginalUri //! [`OriginalUri`]: crate::extract::OriginalUri
//! [`Service`]: tower::Service //! [`Service`]: tower::Service
//! [`Service::poll_ready`]: tower::Service::poll_ready //! [`Service::poll_ready`]: tower::Service::poll_ready
//! [`handle_error`]: routing::Router::handle_error
#![warn( #![warn(
clippy::all, clippy::all,