Commit graph

431 commits

Author SHA1 Message Date
David Pedersen
2bd0310463
New method router (#521)
* Empty crate

* basic setup

* Support `HEAD`

* Add remaining methods

* Impl Debug

* Add `MethodRouter::merge`

* WIP

* Support same route with different methods in different calls

* Update changelog

* Bring back `any` and `any_service`

* Address review feedback
2021-11-16 20:49:07 +01:00
david-perez
3cf8ee3b5e
Drop Sync requirement on the handler function (#522)
Since it doesn't need to be called from different threads at the same
time.
2021-11-16 15:00:56 +01:00
Eray Karatay
e2e9f1ff68
add axum-tutorial to ecosystem (#519) 2021-11-15 07:31:41 +00:00
David Pedersen
20fabd87e9
Add CORS example (#512) 2021-11-13 22:18:14 +01:00
David Pedersen
e58336621d
axum-debug: Version 0.2.0 (#511)
- **breaking:** Removed `debug_router` macro.
- **breaking:** Removed `check_service` function.
- **breaking:** Removed `debug_service` function.
2021-11-13 20:44:13 +01:00
David Pedersen
b9dfea6360
Version 0.3.3 (#510)
- Implement `FromRequest` for [`http::request::Parts`] so it can be used an
  extractor ([#489])
- Implement `IntoResponse` for `http::response::Parts` ([#490])

[#489]: https://github.com/tokio-rs/axum/pull/489
[#490]: https://github.com/tokio-rs/axum/pull/490
[`http::request::Parts`]: https://docs.rs/http/latest/http/request/struct.Parts.html
2021-11-13 20:41:47 +01:00
David Pedersen
6372f93cc5
More clearly document accepting multiple methods (#503)
Seen a few users ask about this and could be documented more clearly.
2021-11-13 20:00:04 +01:00
Jonas Platte
89db85d202
axum-debug: Move axum dependency to dev-dependencies (#506) 2021-11-13 17:38:09 +01:00
David Pedersen
c7b8813c47
Add trybuild tests for axum-debug (#501)
The things are also covered by the doc tests but this also gives us
assertions on the errors produced, which is the whole point of this
crate :)
2021-11-11 20:26:08 +00:00
David Pedersen
26faf0d7a6 Add axum-debug to list of community projects 2021-11-11 19:24:57 +01:00
David Pedersen
34942f3d70
Improve error message for nest("/", _) (#500) 2021-11-11 19:22:25 +01:00
David Pedersen
fb8156f17c
axum-debug readme fixes (#499)
* Fix build status badge in axum-debug

* fix links

* fix one more link
2021-11-11 16:53:07 +00:00
David Pedersen
5da3f34b3e
Clean up axum-debug crate (#498)
* Clean up axum-debug crate

Mostly just brings the crate more in line with the rest of the crates in
the workspace.

I've also removed the axum-debug-macros crate since axum-debug only
contained one re-export from axum-debug-macros. So we didn't need two
crates. Can always bring the "backend" crate back if we need things in
axum-debug that aren't proc-macros.

* Just testing: This should make CI fail

* Misc CI clean up

* fix intentional breakage

* fix changelog

* Remove rustfmt config for now as it gives warnings on stable

* Fix paths
2021-11-11 17:33:33 +01:00
Eray Karatay
f6b47478da
Move axum-debug crate to workspace (#497)
* add axum-debug to workspace

* update readme

* add changes to changelog

* little docs update

* fix the gap

a tab has leaked into workspace Cargo.toml, it must be fixed

* address clippy warnings
2021-11-11 15:18:40 +01:00
Eray Karatay
2507463706
update tls-rustls example (#494) 2021-11-10 15:07:09 +01:00
Kelly Thomas Kline
0990e27964
Correct grammar (#492) 2021-11-10 12:13:47 +00:00
David Pedersen
fdd889525d
Implement FromRequest for http::request::Parts (#489)
Its a convenient way to extract everything from a request except the
body. Also makes sense for axum to provide this since other crates
can't.
2021-11-09 20:37:24 +00:00
David Pedersen
62be8aaa18
Implement IntoResponse for http::response::Parts (#490)
* Implement `IntoResponse` for `http::response::Parts`

Not sure there are many use cases for this but still thinks it makes to
provide since other crates can't.

* Use `Response::from_parts`
2021-11-09 20:50:29 +01:00
Imbolc
2ee66e812f
FromStr based empty_string_as_none implementation (#486) 2021-11-09 13:05:31 +01:00
Jonas Platte
9c77ee0295
Use nightly clippy & rustfmt for more style checks (#487) 2021-11-09 11:53:57 +00:00
Jonas Platte
bcd18a03bc
Split first sentence into its own paragraph in TypedHeader docs (#485) 2021-11-09 12:14:42 +01:00
David Pedersen
3f84eca753 Add axum-handle-error-extract to ecosystem 2021-11-09 09:39:03 +01:00
Folyd
028f8a7242
Fix docs links (#481) 2021-11-09 07:26:53 +00:00
David Pedersen
7710f2cf7f Specify version of axum that axum-handle-error-extract depends on
Seems to be required by `cargo publish`
2021-11-08 19:28:28 +01:00
David Pedersen
7e40312cff
Add axum-handle-error-extract crate (#468)
* Add `axum-handle-error-extract` crate

* fixup

* Fix readme link

* Add `HandleErrorExt` for new error handling middleware

* Revert "fixup"

This reverts commit 83e04954df.
2021-11-08 19:24:54 +01:00
David Pedersen
3d78711e47
Version 0.3.2 (#483)
- **added:** Add `Router::route_layer` for applying middleware that
  will only run on requests that match a route. This is useful for middleware
  that return early, such as authorization ([#474])

[#474]: https://github.com/tokio-rs/axum/pull/474
2021-11-08 18:01:32 +00:00
David Pedersen
7eb2c40b24
Add Router::route_layer (#474)
This addresses something thats been bothering me for some time: Most middleware need to run regardless if the request matches a route or not. For example you don't wanna skip logging for unmatched requests.

However middleware such as authorization only make sense to run for matching requests. This previously wasn't possible to express and you'd have to manually apply the middleware to each handler. Consider this:

```rust
Router::new()
    .route("/foo", get(|| async {}))
    .layer(RequireAuthorizationLayer::bearer("password"));
```

Calling `GET /foo` with an invalid token would receive `401 Unauthorized` as expected however calling some unknown route like `GET /not-found` would also return `401 Unauthorized`. I think this is unexpected and have seen a few users ask questions about it.

It happened because the 404 you'd otherwise see is generated by a fallback service stored on `Router`. When adding a layer to the router the layer would also be applied to the fallback, which in the case of auth means the fallback would never be called for unauthorized requests.

I think what axum does today is the right default however I still think we should support this somehow. Especially since [`extractor_middleware`](https://docs.rs/axum/0.3.1/axum/extract/fn.extractor_middleware.html) is mainly useful for auth but it doesn't work great today due to this gotcha.

This PR proposes adding `Router::layer_on_matching_route` which only applies layers to routes, not the fallback, which fixes the issue. I'm not a big fan of the name `layer_on_matching_route`, would like something shorter, but I think it communicates the purpose decently.

The generics are a bit different since the request body used on the routes and the fallback must match, so layers that changes the request body type are not compatible with `layer_on_matching_route`. Such middleware are very rare so that should be fine.
2021-11-08 18:48:02 +01:00
David Pedersen
5d8ebce211 Add axum-flash to list of community maintained crates 2021-11-07 17:17:13 +01:00
Kelly Thomas Kline
b26fd03810
Add recommendation (#476) 2021-11-07 07:54:53 +00:00
EdorianDark
513c5a694d
Update tracing-subscriber to 0.3 (#472)
Fixes #469
2021-11-06 14:50:23 +00:00
David Pedersen
09bcd8862d
Version 0.3.1 (#473)
- **fixed:** Implement `Clone` for `IntoMakeServiceWithConnectInfo` ([#471])

[#471]: https://github.com/tokio-rs/axum/pull/471
2021-11-06 13:26:23 +00:00
David Pedersen
b3b377d467
Implement Clone for IntoMakeServiceWithConnectInfo (#471)
Fixes https://github.com/tokio-rs/axum/issues/470
2021-11-06 13:06:20 +00:00
Jonas Platte
b4b022da5f
Add turbo.fish to community showcase (#466) 2021-11-05 13:23:53 +01:00
Eray Karatay
394ba31385
update low-level-rustls example (#465) 2021-11-05 12:02:58 +01:00
Frederik-Baetens
07641450c5
Fix links in readme (#464) 2021-11-04 19:57:05 +01:00
David Pedersen
0be0ea6763 Actually run the routing tests 🤦 2021-11-04 12:48:37 +01:00
david-perez
a47d7eca40
Derive Debug for Router instead of implementing manually (#463) 2021-11-04 12:35:50 +01:00
david-perez
071a1b26e6
Fix typos (#461) 2021-11-03 19:03:46 +00:00
David Pedersen
ba4d8a2357
Move axum crate into workspace subfolder (#458)
* Move axum crate into workspace subfolder

Over time I imagine we're gonna have other crates in this repo that
provide utilities or integrations for axum. This prepares for that by
moving the main axum crate into its own folder.

The README situation is a bit annoying because we want `./README.md`
for viewing the repo on github but `axum/README.md` for crates.io. For
now I've just copy/pasted it and added CI step to make sure they're
identical.

* update changelog link

* Add licenses to all examples

* is this how you install `diff`?

* or maybe this is how?

* fix readme links

* like this?

* fix cargo-deny step

* Try making root readme a symlink

* remove compare readme step

not needed since readme in repo root is now a symlink

* Revert "Add licenses to all examples"

This reverts commit ab321b7fb9.
2021-11-03 12:38:48 +01:00
David Pedersen
b60bfd7f34 Mention "axum-typed-websockets" in community ecosystem 2021-11-03 10:26:20 +01:00
David Pedersen
0f1f28062d
Reorganize tests (#456)
* Reorganize tests

This breaks up the large `crate::tests` module by moving some of the
tests into a place that makes more sense. For example tests of JSON
serialization are moved to the `crate::json` module. The remaining routing
tests have been moved to `crate::routing::tests`.

I generally prefer having tests close to the code they're testing. Makes
it easier to see how/if something is tested.

* Try pinning to older version of async-graphql

* Revert "Try pinning to older version of async-graphql"

This reverts commit 2e2cae7d12f5e433a16d6607497d587863f04384.

* don't test examples on 1.54 on CI

* move ci steps around a bit
2021-11-03 10:22:31 +01:00
David Pedersen
420918a53a Clarify change to handling multiple HTTP methods 2021-11-03 09:58:59 +01:00
arctic-alpaca
a442920ba3
Restructure community showcase (#454) 2021-11-03 09:20:01 +01:00
David Pedersen
5367bc65d1 Fix typo 2021-11-03 08:26:13 +01:00
David Pedersen
708988bfae Fix readme example link 2021-11-03 08:25:31 +01:00
Jordan Gould
1c60255b9f
Add readme example project (#450)
* Add project based on the readme example

* Add readme project link to README.md

* Typo correction

* Update examples/readme-example/Cargo.toml

Use tracing-subscriber 0.2 to match other the other examples

Co-authored-by: David Pedersen <david.pdrsn@gmail.com>

* Update README.md

Use original readme phrasing for crate docs

Co-authored-by: David Pedersen <david.pdrsn@gmail.com>

* Rename readme-exmaple to readme

* Revert tracing call to debug from info

Co-authored-by: Jordan Gould <jordan@tineye.com>
Co-authored-by: David Pedersen <david.pdrsn@gmail.com>
2021-11-03 07:23:28 +00:00
Jonas Platte
2ba9cdce45
Fix typos in CHANGELOG.md (#449) 2021-11-02 20:12:27 +00:00
David Pedersen
baefa47634 0.3.0 is out! 2021-11-02 18:41:29 +01:00
David Pedersen
35dba50b32 Fix typo in changelog 2021-11-02 18:40:57 +01:00
David Pedersen
85731a4f1d
Version 0.3.0 (#448)
- Overall:
  - **fixed:** All known compile time issues are resolved, including those with
    `boxed` and those introduced by Rust 1.56 ([#404])
  - **breaking:** The router's type is now always `Router` regardless of how many routes or
    middleware are applied ([#404])

    This means router types are all always nameable:

    ```rust
    fn my_routes() -> Router {
        Router::new().route(
            "/users",
            post(|| async { "Hello, World!" }),
        )
    }
    ```
  - **breaking:** Added feature flags for HTTP1 and JSON. This enables removing a
    few dependencies if your app only uses HTTP2 or doesn't use JSON. Its only a
    breaking change if you depend on axum with `default_features = false`. ([#286])
  - **breaking:** `Route::boxed` and `BoxRoute` have been removed as they're no longer
    necessary ([#404])
  - **breaking:** `Nested`, `Or` types are now private. They no longer had to be
    public because `Router` is internally boxed ([#404])
  - **breaking:** Remove `routing::Layered` as it didn't actually do anything and
    thus wasn't necessary
  - **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public
    dependencies
  - **breaking:** `body::BoxBody` is now a type alias for
    `http_body::combinators::UnsyncBoxBody` and thus is no longer `Sync`. This
    is because bodies are streams and requiring streams to be `Sync` is
    unnecessary.
  - **added:** Implement `IntoResponse` for `http_body::combinators::UnsyncBoxBody`.
  - **added:** Add `Handler::into_make_service` for serving a handler without a
    `Router`.
  - **added:** Add `Handler::into_make_service_with_connect_info` for serving a
    handler without a `Router`, and storing info about the incoming connection.
  - **breaking:** axum's minimum support rust version is not 1.54
- Routing:
  - Big internal refactoring of routing leading to several improvements ([#363])
    - **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported.
    - **fixed:** The order routes are added in no longer matters.
    - **fixed:** Adding a conflicting route will now cause a panic instead of silently making
      a route unreachable.
    - **fixed:** Route matching is faster as number of routes increase.
  - **fixed:** Correctly handle trailing slashes in routes:
    - If a route with a trailing slash exists and a request without a trailing
      slash is received, axum will send a 301 redirection to the route with the
      trailing slash.
    - Or vice versa if a route without a trailing slash exists and a request
      with a trailing slash is received.
    - This can be overridden by explicitly defining two routes: One with and one
      without trailing a slash.
  - **breaking:** Method routing for handlers have been moved from `axum::handler`
    to `axum::routing`. So `axum::handler::get` now lives at `axum::routing::get`
    ([#405])
  - **breaking:** Method routing for services have been moved from `axum::service`
    to `axum::routing`. So `axum::service::get` now lives at, etc.
    `axum::routing::service_method_routing::get`, etc. ([#405])
  - **breaking:** `Router::or` renamed to `Router::merge` and will now panic on
    overlapping routes. It now only accepts `Router`s and not general `Service`s.
    Use `Router::fallback` for adding fallback routes ([#408])
  - **added:** `Router::fallback` for adding handlers for request that didn't
    match any routes. `Router::fallback` must be use instead of `nest("/", _)` ([#408])
  - **breaking:** `EmptyRouter` has been renamed to `MethodNotAllowed` as its only
    used in method routers and not in path routers (`Router`)
  - **breaking:** Remove support for routing based on the `CONNECT` method. An
    example of combining axum with and HTTP proxy can be found [here][proxy] ([#428])
- Extractors:
  - **fixed:** Expand accepted content types for JSON requests ([#378])
  - **fixed:** Support deserializing `i128` and `u128` in `extract::Path`
  - **breaking:** Automatically do percent decoding in `extract::Path`
    ([#272])
  - **breaking:** Change `Connected::connect_info` to return `Self` and remove
    the associated type `ConnectInfo` ([#396])
  - **added:** Add `extract::MatchedPath` for accessing path in router that
    matched the request ([#412])
- Error handling:
  - **breaking:** Simplify error handling model ([#402]):
    - All services part of the router are now required to be infallible.
    - Error handling utilities have been moved to an `error_handling` module.
    - `Router::check_infallible` has been removed since routers are always
      infallible with the error handling changes.
    - Error handling closures must now handle all errors and thus always return
      something that implements `IntoResponse`.

    With these changes handling errors from fallible middleware is done like so:

    ```rust,no_run
    use axum::{
        routing::get,
        http::StatusCode,
        error_handling::HandleErrorLayer,
        response::IntoResponse,
        Router, BoxError,
    };
    use tower::ServiceBuilder;
    use std::time::Duration;

    let middleware_stack = ServiceBuilder::new()
        // Handle errors from middleware
        //
        // This middleware most be added above any fallible
        // ones if you're using `ServiceBuilder`, due to how ordering works
        .layer(HandleErrorLayer::new(handle_error))
        // Return an error after 30 seconds
        .timeout(Duration::from_secs(30));

    let app = Router::new()
        .route("/", get(|| async { /* ... */ }))
        .layer(middleware_stack);

    fn handle_error(_error: BoxError) -> impl IntoResponse {
        StatusCode::REQUEST_TIMEOUT
    }
    ```

    And handling errors from fallible leaf services is done like so:

    ```rust
    use axum::{
        Router, service,
        body::Body,
        routing::service_method_routing::get,
        response::IntoResponse,
        http::{Request, Response},
        error_handling::HandleErrorExt, // for `.handle_error`
    };
    use std::{io, convert::Infallible};
    use tower::service_fn;

    let app = Router::new()
        .route(
            "/",
            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) -> impl IntoResponse {
        // ...
    }
    ```
- Misc:
  - `InvalidWebsocketVersionHeader` has been renamed to `InvalidWebSocketVersionHeader` ([#416])
  - `WebsocketKeyHeaderMissing` has been renamed to `WebSocketKeyHeaderMissing` ([#416])

[#339]: https://github.com/tokio-rs/axum/pull/339
[#286]: https://github.com/tokio-rs/axum/pull/286
[#272]: https://github.com/tokio-rs/axum/pull/272
[#378]: https://github.com/tokio-rs/axum/pull/378
[#363]: https://github.com/tokio-rs/axum/pull/363
[#396]: https://github.com/tokio-rs/axum/pull/396
[#402]: https://github.com/tokio-rs/axum/pull/402
[#404]: https://github.com/tokio-rs/axum/pull/404
[#405]: https://github.com/tokio-rs/axum/pull/405
[#408]: https://github.com/tokio-rs/axum/pull/408
[#412]: https://github.com/tokio-rs/axum/pull/412
[#416]: https://github.com/tokio-rs/axum/pull/416
[#428]: https://github.com/tokio-rs/axum/pull/428
[proxy]: https://github.com/tokio-rs/axum/blob/main/examples/http-proxy/src/main.rs
2021-11-02 18:14:41 +01:00