Change WebSocket API to use an extractor - #121
Merged
Merged
Conversation
Fixes #111 Example usage: ```rust use axum::{ prelude::*, extract::ws::{WebSocketUpgrade, WebSocket}, response::IntoResponse, }; let app = route("/ws", get(handler)); async fn handler(ws: WebSocketUpgrade) -> impl IntoResponse { ws.on_upgrade(handle_socket) } async fn handle_socket(mut socket: WebSocket) { while let Some(msg) = socket.recv().await { let msg = if let Ok(msg) = msg { msg } else { // client disconnected return; }; if socket.send(msg).await.is_err() { // client disconnected return; } } } ```
Merged
davidpdrsn
added a commit
that referenced
this pull request
Aug 23, 2021
- Overall:
- **fixed:** Overall compile time improvements. If you're having issues with compile time
please file an issue! ([#184](#184)) ([#198](#198)) ([#220](#220))
- **changed:** Remove `prelude`. Explicit imports are now required ([#195](#195))
- Routing:
- **added:** Add dedicated `Router` to replace the `RoutingDsl` trait ([#214](#214))
- **added:** Add `Router::or` for combining routes ([#108](#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](#224))
- **fixed:** `get` routes will now also be called for `HEAD` requests but will always have
the response body removed ([#129](#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](#215))
- **changed:** Implement `routing::MethodFilter` via [`bitflags`](https://crates.io/crates/bitflags) ([#158](#158))
- **changed:** Move `handle_error` from `ServiceExt` to `service::OnMethod` ([#160](#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](#146))
- **added:** Implement `std::error::Error` for all rejections ([#153](#153))
- **added:** Add `OriginalUri` for extracting original request URI in nested services ([#197](#197))
- **added:** Implement `FromRequest` for `http::Extensions` ([#169](#169))
- **added:** Make `RequestParts::{new, try_into_request}` public so extractors can be used outside axum ([#194](#194))
- **added:** Implement `FromRequest` for `axum::body::Body` ([#241](#241))
- **changed:** Removed `extract::UrlParams` and `extract::UrlParamsMap`. Use `extract::Path` instead ([#154](#154))
- **changed:** `extractor_middleware` now requires `RequestBody: Default` ([#167](#167))
- **changed:** Convert `RequestAlreadyExtracted` to an enum with each possible error variant ([#167](#167))
- **changed:** `extract::BodyStream` is no longer generic over the request body ([#234](#234))
- **changed:** `extract::Body` has been renamed to `extract::RawBody` to avoid conflicting with `body::Body` ([#233](#233))
- **changed:** `RequestParts` changes ([#153](#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](#153)) ([#154](#154))
- Responses:
- **added:** Add `Headers` for easily customizing headers on a response ([#193](#193))
- **added:** Add `Redirect` response ([#192](#192))
- **added:** Add `body::StreamBody` for easily responding with a stream of byte chunks ([#237](#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](#86))
- **changed:** `tower::util::Either` no longer implements `IntoResponse` ([#229](#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](#98))
- **changed:** Remove `axum::sse`. Its been replaced by `axum::response::sse` ([#98](#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](#121))
- **changed:** Make WebSocket `Message` an enum ([#116](#116))
- **changed:** `WebSocket` now uses `Error` as its error type ([#150](#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](#218))
- **changed:** Replace `body::BoxStdError` with `axum::Error`, which supports downcasting ([#150](#150))
- **changed:** `EmptyRouter` now requires the response body to implement `Send + Sync + 'static'` ([#108](#108))
- **changed:** `Router::check_infallible` now returns a `CheckInfallible` service. This
is to improve compile times ([#198](#198))
- **changed:** `Router::into_make_service` now returns `routing::IntoMakeService` rather than
`tower::make::Shared` ([#229](#229))
- **changed:** All usage of `tower::BoxError` has been replaced with `axum::BoxError` ([#229](#229))
- **changed:** Several response future types have been moved into dedicated
`future` modules ([#133](#133))
- **changed:** `EmptyRouter`, `ExtractorMiddleware`, `ExtractorMiddlewareLayer`,
and `QueryStringMissing` no longer implement `Copy` ([#132](#132))
- **changed:** `service::OnMethod`, `handler::OnMethod`, and `routing::Nested` have new response future types ([#157](#157))
saad-aistack
added a commit
to saad-aistack/rust-high-perf-api
that referenced
this pull request
Mar 26, 2026
- Overall:
- **fixed:** Overall compile time improvements. If you're having issues with compile time
please file an issue! ([#184](tokio-rs/axum#184)) ([#198](tokio-rs/axum#198)) ([#220](tokio-rs/axum#220))
- **changed:** Remove `prelude`. Explicit imports are now required ([#195](tokio-rs/axum#195))
- Routing:
- **added:** Add dedicated `Router` to replace the `RoutingDsl` trait ([#214](tokio-rs/axum#214))
- **added:** Add `Router::or` for combining routes ([#108](tokio-rs/axum#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](tokio-rs/axum#224))
- **fixed:** `get` routes will now also be called for `HEAD` requests but will always have
the response body removed ([#129](tokio-rs/axum#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](tokio-rs/axum#215))
- **changed:** Implement `routing::MethodFilter` via [`bitflags`](https://crates.io/crates/bitflags) ([#158](tokio-rs/axum#158))
- **changed:** Move `handle_error` from `ServiceExt` to `service::OnMethod` ([#160](tokio-rs/axum#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](tokio-rs/axum#146))
- **added:** Implement `std::error::Error` for all rejections ([#153](tokio-rs/axum#153))
- **added:** Add `OriginalUri` for extracting original request URI in nested services ([#197](tokio-rs/axum#197))
- **added:** Implement `FromRequest` for `http::Extensions` ([#169](tokio-rs/axum#169))
- **added:** Make `RequestParts::{new, try_into_request}` public so extractors can be used outside axum ([#194](tokio-rs/axum#194))
- **added:** Implement `FromRequest` for `axum::body::Body` ([#241](tokio-rs/axum#241))
- **changed:** Removed `extract::UrlParams` and `extract::UrlParamsMap`. Use `extract::Path` instead ([#154](tokio-rs/axum#154))
- **changed:** `extractor_middleware` now requires `RequestBody: Default` ([#167](tokio-rs/axum#167))
- **changed:** Convert `RequestAlreadyExtracted` to an enum with each possible error variant ([#167](tokio-rs/axum#167))
- **changed:** `extract::BodyStream` is no longer generic over the request body ([#234](tokio-rs/axum#234))
- **changed:** `extract::Body` has been renamed to `extract::RawBody` to avoid conflicting with `body::Body` ([#233](tokio-rs/axum#233))
- **changed:** `RequestParts` changes ([#153](tokio-rs/axum#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](tokio-rs/axum#153)) ([#154](tokio-rs/axum#154))
- Responses:
- **added:** Add `Headers` for easily customizing headers on a response ([#193](tokio-rs/axum#193))
- **added:** Add `Redirect` response ([#192](tokio-rs/axum#192))
- **added:** Add `body::StreamBody` for easily responding with a stream of byte chunks ([#237](tokio-rs/axum#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](tokio-rs/axum#86))
- **changed:** `tower::util::Either` no longer implements `IntoResponse` ([#229](tokio-rs/axum#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](tokio-rs/axum#98))
- **changed:** Remove `axum::sse`. Its been replaced by `axum::response::sse` ([#98](tokio-rs/axum#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](tokio-rs/axum#121))
- **changed:** Make WebSocket `Message` an enum ([#116](tokio-rs/axum#116))
- **changed:** `WebSocket` now uses `Error` as its error type ([#150](tokio-rs/axum#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](tokio-rs/axum#218))
- **changed:** Replace `body::BoxStdError` with `axum::Error`, which supports downcasting ([#150](tokio-rs/axum#150))
- **changed:** `EmptyRouter` now requires the response body to implement `Send + Sync + 'static'` ([#108](tokio-rs/axum#108))
- **changed:** `Router::check_infallible` now returns a `CheckInfallible` service. This
is to improve compile times ([#198](tokio-rs/axum#198))
- **changed:** `Router::into_make_service` now returns `routing::IntoMakeService` rather than
`tower::make::Shared` ([#229](tokio-rs/axum#229))
- **changed:** All usage of `tower::BoxError` has been replaced with `axum::BoxError` ([#229](tokio-rs/axum#229))
- **changed:** Several response future types have been moved into dedicated
`future` modules ([#133](tokio-rs/axum#133))
- **changed:** `EmptyRouter`, `ExtractorMiddleware`, `ExtractorMiddlewareLayer`,
and `QueryStringMissing` no longer implement `Copy` ([#132](tokio-rs/axum#132))
- **changed:** `service::OnMethod`, `handler::OnMethod`, and `routing::Nested` have new response future types ([#157](tokio-rs/axum#157))
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #111
Example usage: