* Make `IntoMakeService(WithConnectInfo)?` work with any Service
* Add `Handler::{into_make_service, into_make_service_with_connect_info}`
These are useful if you want to run a handler without a `Router`, for
example to make a proxy.
As we learned [in Tonic] bodies don't need to be `Sync` because they can
only be polled from one thread at a time.
This changes axum's bodies to no longer require `Sync` and makes
`BoxBody` an alias for `UnsyncBoxBody<Bytes, axum::Error>`.
[in Tonic]: https://github.com/hyperium/tonic/issues/117
This reworks axum's docs in an attempt to make things easier to find. Previously I wasn't a fan of those docs for the same topic were spread across the root module docs and more specific places like types and methods.
This changes it such that the root module docs only gives a high level introduction to a topic, perhaps with a small example, and then link to other places where all the details are. This means `Router` is now the single place to learn about routing, and etc for the topics like handlers and error handling.
axum uses `impl Layer for ServiceBuilder` internally which requires
tower 0.4.10. Making that explicit should help users updating to axum
0.3 without also having to manually bump their tower dependency.
For 0.3 I'm thinking about some changes I wanna make to the docs. I
don't like how information is currently spread over so many places.
Still thinking about how I wanna re-organize it.
However I do think it makes sense to break the root module docs into
separate files that get included with `#![doc = include_str!("file")]`.
Makes working on a single section easier and more focused. It looks the
same for the user reading the docs.
This means axum's MSRV is now 1.54 but since thats two releases ago I'm
fine with that.
This panics if you pass a `Router` to `Router::route`. Thats invalid and
will result in unreachable routes.
Unfortunately I don't think we can make it a type error while supporting
general `Service`s. So I think this is a decent workaround.
Fixes https://github.com/tokio-rs/axum/issues/174
When fixing bugs with `MatchedPath` (introduced to fix https://github.com/tokio-rs/axum/issues/386) I realized nesting could basically be implemented using regular routes, if we can detect that the service passed to `nest` is in fact a `Router`. Then we can transfer over all its routes and add the prefix.
This makes nesting much simpler in general and should also be slightly faster since we're no longer nesting routers.
We stripped the prefix before calling any middleware. Instead the prefix
should be stripped just before calling the actual route. This way
middleware still see the full URI, as it used to work in 0.2.
Fixes#419
While thinking about #419 I realized that `main` had a bug where
middleware wouldn't be called if no route matched the incoming request.
`Router` would just directly return a 404 without calling any
middleware.
This fixes by making the fallback default to a service that always
returns 404 and always calling that if no route matches.
Layers applied to the router is then also applied to the fallback.
Unfortunately this breaks #380 but I don't currently see a way to
support both. Auth middleware need to run _after_ routing because you
don't care about auth for unknown paths, but logging middleware need to
run _before_ routing because they do care about seeing requests for
unknown paths so they can log them...
Part of #419
- Static vs dynamic paths are now supported meaning `/foo` and `/:key`
are not considered to overlap.
- A bug we hit regarding trailing slashes is fixed.
This remove tower-http from axum's public API. I would like to be able
to make breaking releases of tower-http without also having to ship a
breaking release of axum.
With https://github.com/tokio-rs/axum/pull/404 and https://github.com/tokio-rs/axum/pull/402 all routes now have the same types and thus we don't need to nest them but can instead store them all in a map. This simplifies the routing quite a bit and is faster as well.
High level changes:
- Routes are now stored in a `HashMap<RouteId, Route<B>>`.
- `Router::or` is renamed to `Router::merge` because thats what it does now. It copies all routes from one router to another. This also means overlapping routes will cause a panic which is nice win.
- `Router::merge` now only accepts `Router`s so added `Router::fallback` for adding a global 404 handler.
- The `Or` service has been removed.
- `Router::layer` now only adds layers to the routes you actually have meaning middleware runs _after_ routing. I believe that addresses https://github.com/tokio-rs/axum/issues/380 but will test that on another branch.
In #363 I added `MaybeSharedNode` which makes `Router` faster to clone
_if_ you're using `into_make_service`. However I would like instead like
to find a solution that works even when you're not using
`into_make_service`.
Using an `Arc<RwLock<Node<_>>>` is probably the only solution but would
like to experiment. For now I'm gonna rollback `MaybeSharedNode`.
Changing it wont require user facing changes.
* "matchit" based router
* Update changelog
* Remove dependency on `regex`
* Docs
* Fix typos
* Also mention route order in root module docs
* Update CHANGELOG.md
Co-authored-by: Jonas Platte <[email protected]>
* Document that `/:key` and `/foo` overlaps
* Provide good error message for wildcards in routes
* minor clean ups
* Make `Router` cheaper to clone
* Ensure middleware still only applies to routes above
* Remove call to issues from changelog
We're aware of the short coming :)
* Fix tests on 1.51
Co-authored-by: Jonas Platte <[email protected]>
I've been thinking that having an associated type probably isn't
necessary. I imagine most users are either using `SocketAddr` to the
remote connection IP, or writing their own connection struct.
* Expand accepted content types for JSON requests
Fixes https://github.com/tokio-rs/axum/issues/375
* changelog
* add test for content type without spaces
* Don't accept `text/json`
* small clean up
* Document debugging handler type errors with "axum-debug"
* Apply suggestions from code review
Co-authored-by: Jonas Platte <[email protected]>
Co-authored-by: Jonas Platte <[email protected]>
* Percent decode automatically in `extract::Path`
Fixes https://github.com/tokio-rs/axum/issues/261
* return an error if path param contains invalid utf-8
* Mention automatic decoding in the docs
* Update changelog: This is a breaking change
* cleanup
* fix tests
* Improve performance of `BoxRoute`
This is based on #315 but slightly shorter.
It removes the need for a `tower::buffer::Buffer` in `BoxRoute` which
improves performance.
* changelog
Co-authored-by: Programatik <[email protected]>
This changes the test setup to use our own client rather than using
reqwest directly. Allows us to add several quality of life features like
always unwrapping results.
* Improve extractor docs
- Moves things from the `extract` module docs to the root module docs to
make them more discoverable
- Adds section showing commonly used extractors
- More clarity around multiple extractors that mutate the request
* english...
0.2.3 (26. August, 2021)
- **fixed:** Fix accidental breaking change introduced by internal refactor.
`BoxRoute` used to be `Sync` but was accidental made `!Sync` ([#273](https://github.com/tokio-rs/axum/pull/273))
Boxing a service normally means using `tower::util::BoxService`. That
doesn't implement `Clone` however so normally I had been combining it
with `Buffer` to get that.
But recently I discovered https://github.com/dtolnay/dyn-clone which
makes it possible to clone trait objects. So this adds a new internal
utility called `CloneBoxService` which replaces the previous
`BoxService` + `Buffer` combo in `BoxRoute`.
I'll investigate upstreaming that to tower. I think it makes sense there
since box + clone is quite a common need.
- Overall:
- **fixed:** Overall compile time improvements. If you're having issues with compile time
please file an issue! ([#184](https://github.com/tokio-rs/axum/pull/184)) ([#198](https://github.com/tokio-rs/axum/pull/198)) ([#220](https://github.com/tokio-rs/axum/pull/220))
- **changed:** Remove `prelude`. Explicit imports are now required ([#195](https://github.com/tokio-rs/axum/pull/195))
- Routing:
- **added:** Add dedicated `Router` to replace the `RoutingDsl` trait ([#214](https://github.com/tokio-rs/axum/pull/214))
- **added:** Add `Router::or` for combining routes ([#108](https://github.com/tokio-rs/axum/pull/108))
- **fixed:** Support matching different HTTP methods for the same route that aren't defined
together. So `Router::new().route("/", get(...)).route("/", post(...))` now
accepts both `GET` and `POST`. Previously only `POST` would be accepted ([#224](https://github.com/tokio-rs/axum/pull/224))
- **fixed:** `get` routes will now also be called for `HEAD` requests but will always have
the response body removed ([#129](https://github.com/tokio-rs/axum/pull/129))
- **changed:** Replace `axum::route(...)` with `axum::Router::new().route(...)`. This means
there is now only one way to create a new router. Same goes for
`axum::routing::nest`. ([#215](https://github.com/tokio-rs/axum/pull/215))
- **changed:** Implement `routing::MethodFilter` via [`bitflags`](https://crates.io/crates/bitflags) ([#158](https://github.com/tokio-rs/axum/pull/158))
- **changed:** Move `handle_error` from `ServiceExt` to `service::OnMethod` ([#160](https://github.com/tokio-rs/axum/pull/160))
With these changes this app using 0.1:
```rust
use axum::{extract::Extension, prelude::*, routing::BoxRoute, AddExtensionLayer};
let app = route("/", get(|| async { "hi" }))
.nest("/api", api_routes())
.layer(AddExtensionLayer::new(state));
fn api_routes() -> BoxRoute<Body> {
route(
"/users",
post(|Extension(state): Extension<State>| async { "hi from nested" }),
)
.boxed()
}
```
Becomes this in 0.2:
```rust
use axum::{
extract::Extension,
handler::{get, post},
routing::BoxRoute,
Router,
};
let app = Router::new()
.route("/", get(|| async { "hi" }))
.nest("/api", api_routes());
fn api_routes() -> Router<BoxRoute> {
Router::new()
.route(
"/users",
post(|Extension(state): Extension<State>| async { "hi from nested" }),
)
.boxed()
}
```
- Extractors:
- **added:** Make `FromRequest` default to being generic over `body::Body` ([#146](https://github.com/tokio-rs/axum/pull/146))
- **added:** Implement `std::error::Error` for all rejections ([#153](https://github.com/tokio-rs/axum/pull/153))
- **added:** Add `OriginalUri` for extracting original request URI in nested services ([#197](https://github.com/tokio-rs/axum/pull/197))
- **added:** Implement `FromRequest` for `http::Extensions` ([#169](https://github.com/tokio-rs/axum/pull/169))
- **added:** Make `RequestParts::{new, try_into_request}` public so extractors can be used outside axum ([#194](https://github.com/tokio-rs/axum/pull/194))
- **added:** Implement `FromRequest` for `axum::body::Body` ([#241](https://github.com/tokio-rs/axum/pull/241))
- **changed:** Removed `extract::UrlParams` and `extract::UrlParamsMap`. Use `extract::Path` instead ([#154](https://github.com/tokio-rs/axum/pull/154))
- **changed:** `extractor_middleware` now requires `RequestBody: Default` ([#167](https://github.com/tokio-rs/axum/pull/167))
- **changed:** Convert `RequestAlreadyExtracted` to an enum with each possible error variant ([#167](https://github.com/tokio-rs/axum/pull/167))
- **changed:** `extract::BodyStream` is no longer generic over the request body ([#234](https://github.com/tokio-rs/axum/pull/234))
- **changed:** `extract::Body` has been renamed to `extract::RawBody` to avoid conflicting with `body::Body` ([#233](https://github.com/tokio-rs/axum/pull/233))
- **changed:** `RequestParts` changes ([#153](https://github.com/tokio-rs/axum/pull/153))
- `method` new returns an `&http::Method`
- `method_mut` new returns an `&mut http::Method`
- `take_method` has been removed
- `uri` new returns an `&http::Uri`
- `uri_mut` new returns an `&mut http::Uri`
- `take_uri` has been removed
- **changed:** Remove several rejection types that were no longer used ([#153](https://github.com/tokio-rs/axum/pull/153)) ([#154](https://github.com/tokio-rs/axum/pull/154))
- Responses:
- **added:** Add `Headers` for easily customizing headers on a response ([#193](https://github.com/tokio-rs/axum/pull/193))
- **added:** Add `Redirect` response ([#192](https://github.com/tokio-rs/axum/pull/192))
- **added:** Add `body::StreamBody` for easily responding with a stream of byte chunks ([#237](https://github.com/tokio-rs/axum/pull/237))
- **changed:** Add associated `Body` and `BodyError` types to `IntoResponse`. This is
required for returning responses with bodies other than `hyper::Body` from
handlers. See the docs for advice on how to implement `IntoResponse` ([#86](https://github.com/tokio-rs/axum/pull/86))
- **changed:** `tower::util::Either` no longer implements `IntoResponse` ([#229](https://github.com/tokio-rs/axum/pull/229))
This `IntoResponse` from 0.1:
```rust
use axum::{http::Response, prelude::*, response::IntoResponse};
struct MyResponse;
impl IntoResponse for MyResponse {
fn into_response(self) -> Response<Body> {
Response::new(Body::empty())
}
}
```
Becomes this in 0.2:
```rust
use axum::{body::Body, http::Response, response::IntoResponse};
struct MyResponse;
impl IntoResponse for MyResponse {
type Body = Body;
type BodyError = <Self::Body as axum::body::HttpBody>::Error;
fn into_response(self) -> Response<Self::Body> {
Response::new(Body::empty())
}
}
```
- SSE:
- **added:** Add `response::sse::Sse`. This implements SSE using a response rather than a service ([#98](https://github.com/tokio-rs/axum/pull/98))
- **changed:** Remove `axum::sse`. Its been replaced by `axum::response::sse` ([#98](https://github.com/tokio-rs/axum/pull/98))
Handler using SSE in 0.1:
```rust
use axum::{
prelude::*,
sse::{sse, Event},
};
use std::convert::Infallible;
let app = route(
"/",
sse(|| async {
let stream = futures::stream::iter(vec![Ok::<_, Infallible>(
Event::default().data("hi there!"),
)]);
Ok::<_, Infallible>(stream)
}),
);
```
Becomes this in 0.2:
```rust
use axum::{
handler::get,
response::sse::{Event, Sse},
Router,
};
use std::convert::Infallible;
let app = Router::new().route(
"/",
get(|| async {
let stream = futures::stream::iter(vec![Ok::<_, Infallible>(
Event::default().data("hi there!"),
)]);
Sse::new(stream)
}),
);
```
- WebSockets:
- **changed:** Change WebSocket API to use an extractor plus a response ([#121](https://github.com/tokio-rs/axum/pull/121))
- **changed:** Make WebSocket `Message` an enum ([#116](https://github.com/tokio-rs/axum/pull/116))
- **changed:** `WebSocket` now uses `Error` as its error type ([#150](https://github.com/tokio-rs/axum/pull/150))
Handler using WebSockets in 0.1:
```rust
use axum::{
prelude::*,
ws::{ws, WebSocket},
};
let app = route(
"/",
ws(|socket: WebSocket| async move {
// do stuff with socket
}),
);
```
Becomes this in 0.2:
```rust
use axum::{
extract::ws::{WebSocket, WebSocketUpgrade},
handler::get,
Router,
};
let app = Router::new().route(
"/",
get(|ws: WebSocketUpgrade| async move {
ws.on_upgrade(|socket: WebSocket| async move {
// do stuff with socket
})
}),
);
```
- Misc
- **added:** Add default feature `tower-log` which exposes `tower`'s `log` feature. ([#218](https://github.com/tokio-rs/axum/pull/218))
- **changed:** Replace `body::BoxStdError` with `axum::Error`, which supports downcasting ([#150](https://github.com/tokio-rs/axum/pull/150))
- **changed:** `EmptyRouter` now requires the response body to implement `Send + Sync + 'static'` ([#108](https://github.com/tokio-rs/axum/pull/108))
- **changed:** `Router::check_infallible` now returns a `CheckInfallible` service. This
is to improve compile times ([#198](https://github.com/tokio-rs/axum/pull/198))
- **changed:** `Router::into_make_service` now returns `routing::IntoMakeService` rather than
`tower::make::Shared` ([#229](https://github.com/tokio-rs/axum/pull/229))
- **changed:** All usage of `tower::BoxError` has been replaced with `axum::BoxError` ([#229](https://github.com/tokio-rs/axum/pull/229))
- **changed:** Several response future types have been moved into dedicated
`future` modules ([#133](https://github.com/tokio-rs/axum/pull/133))
- **changed:** `EmptyRouter`, `ExtractorMiddleware`, `ExtractorMiddlewareLayer`,
and `QueryStringMissing` no longer implement `Copy` ([#132](https://github.com/tokio-rs/axum/pull/132))
- **changed:** `service::OnMethod`, `handler::OnMethod`, and `routing::Nested` have new response future types ([#157](https://github.com/tokio-rs/axum/pull/157))
I just had a thought: Why should `response::Headers` be generic, but
`body::StreamBody` should not? `StreamBody` previously boxed the stream
to erase the generics. So we had `response::Headers<T>` but
`body::StreamBody`, without generics.
After thinking about it I think it actually makes sense for responses to
remain generic because you're able to use `impl IntoResponse` so you
don't have to name the generics.
Whereas in the case of `BodyStream` (an extractor) you cannot use `impl Trait`
so it makes sense to box the inner body to make the type easier to name. Besides,
`BodyStream` is mostly useful when the request body isn't `hyper::Body`, as
that already implements `Stream`.
This adds `StreamBody` which converts a `Stream` of `Bytes` into a `http_body::Body`.
---
As suggested by Kestrer on Discord it would make sense for axum to provide different kinds of body types other than `Empty`, `Full`, and `hyper::Body`. There is also some talk about [splitting up `hyper::Body`](https://github.com/hyperium/hyper/issues/2345) so this can be seen as getting started on that effort. axum's body types could be moved to hyper or http-body if thats the direction we decide on.
The types I'm thinking about adding are:
- `StreamBody`- added in this PR
- `AsyncReadBody` - similar to [http-body#41](https://github.com/hyperium/http-body/pull/41/files)
- `ChannelBody` - similar to `hyper::Body::channel`
I think `BodyStream` is more useful without being generic over the
request body.
I'm also looking into adding a response body from a stream called
`StreamBody` which will work pretty much opposite to this.
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 removes a small foot gun from the routing.
This means matching different HTTP methods for the same route that
aren't defined together now works.
So `Router::new().route("/", get(...)).route("/", post(...))` now
accepts both `GET` and `POST`. Previously only `POST` would be accepted.