diff --git a/axum/src/docs/extract.md b/axum/src/docs/extract.md
index 238273fe..ba5d2784 100644
--- a/axum/src/docs/extract.md
+++ b/axum/src/docs/extract.md
@@ -136,31 +136,83 @@ async fn get_user_things(
# };
```
-Take care of the order in which you apply extractors as some will mutate the
-request. For example extractors that consume the request body can only be
-applied once. The same is true for [`Request`], which consumes the entire
-request:
+Extractors always run in the order of the function parameters that is from
+left to right.
+
+# Be careful when extracting `Request`
+
+[`Request`] is itself an extractor:
```rust,no_run
-use axum::{
- routing::get,
- http::Request,
- body::Body,
- Router,
-};
+use axum::{http::Request, body::Body};
async fn handler(request: Request
) {
// ...
}
-
-let app = Router::new().route("/", get(handler));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
```
-Extractors always run in the order of the function parameters that is from
-left to right.
+However be careful when combining it with other extractors since it will consume
+all extensions and the request body. Therefore it is recommended to always apply
+the request extractor last:
+
+```rust,no_run
+use axum::{http::Request, Extension, body::Body};
+
+// this will fail at runtime since `Request` will have consumed all the
+// extensions so `Extension` will be missing
+async fn broken(
+ request: Request,
+ Extension(state): Extension,
+) {
+ // ...
+}
+
+// this will work since we extract `Extension` before `Request`
+async fn works(
+ Extension(state): Extension,
+ request: Request,
+) {
+ // ...
+}
+
+#[derive(Clone)]
+struct State {};
+```
+
+# Extracting request bodies
+
+Since request bodies are asynchronous streams they can only be extracted once:
+
+```rust,no_run
+use axum::{Json, http::Request, body::{Bytes, Body}};
+use serde_json::Value;
+
+// this will fail at runtime since `Json` and `Bytes` both attempt to extract
+// the body
+//
+// the solution is to only extract the body once so remove either
+// `body_json: Json` or `body_bytes: Bytes`
+async fn broken(
+ body_json: Json,
+ body_bytes: Bytes,
+) {
+ // ...
+}
+
+// this doesn't work either for the same reason: `Bytes` and `Request`
+// both extract the body
+async fn also_broken(
+ body_json: Json,
+ request: Request,
+) {
+ // ...
+}
+```
+
+Also keep this in mind if you extract or otherwise consume the body in
+middleware. You either need to not extract the body in handlers or make sure
+your middleware reinserts the body using [`RequestParts::body_mut`] so it's
+available to handlers.
# Optional extractors
@@ -514,3 +566,4 @@ let app = Router::new()
[customize-extractor-error]: https://github.com/tokio-rs/axum/blob/main/examples/customize-extractor-error/src/main.rs
[`HeaderMap`]: https://docs.rs/http/latest/http/header/struct.HeaderMap.html
[`Request`]: https://docs.rs/http/latest/http/struct.Request.html
+[`RequestParts::body_mut`]: crate::extract::RequestParts::body_mut