Skip to content

Commit

Permalink
Backport changes from main to v0.6.x (#2141)
Browse files Browse the repository at this point in the history
Co-authored-by: David Pedersen <[email protected]>
  • Loading branch information
jplatte and davidpdrsn authored Aug 3, 2023
1 parent a25ed29 commit 68333b2
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 5 deletions.
4 changes: 3 additions & 1 deletion axum-extra/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning].

# Unreleased

- None.
- **added:** `Clone` implementation for `ErasedJson` ([#2142])

[#2142]: https://github.com/tokio-rs/axum/pull/2142

# 0.7.6 (02. August, 2023)

Expand Down
18 changes: 14 additions & 4 deletions axum-extra/src/response/erased_json.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use axum::{
http::{header, HeaderValue, StatusCode},
response::{IntoResponse, Response},
Expand Down Expand Up @@ -29,21 +31,29 @@ use serde::Serialize;
/// }
/// ```
#[cfg_attr(docsrs, doc(cfg(feature = "erased-json")))]
#[derive(Debug)]
#[derive(Clone, Debug)]
#[must_use]
pub struct ErasedJson(serde_json::Result<Bytes>);
pub struct ErasedJson(Result<Bytes, Arc<serde_json::Error>>);

impl ErasedJson {
/// Create an `ErasedJson` by serializing a value with the compact formatter.
pub fn new<T: Serialize>(val: T) -> Self {
let mut bytes = BytesMut::with_capacity(128);
Self(serde_json::to_writer((&mut bytes).writer(), &val).map(|_| bytes.freeze()))
let result = match serde_json::to_writer((&mut bytes).writer(), &val) {
Ok(()) => Ok(bytes.freeze()),
Err(e) => Err(Arc::new(e)),
};
Self(result)
}

/// Create an `ErasedJson` by serializing a value with the pretty formatter.
pub fn pretty<T: Serialize>(val: T) -> Self {
let mut bytes = BytesMut::with_capacity(128);
Self(serde_json::to_writer_pretty((&mut bytes).writer(), &val).map(|_| bytes.freeze()))
let result = match serde_json::to_writer_pretty((&mut bytes).writer(), &val) {
Ok(()) => Ok(bytes.freeze()),
Err(e) => Err(Arc::new(e)),
};
Self(result)
}
}

Expand Down
3 changes: 3 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **added:** `WebSocketUpgrade::write_buffer_size` and `WebSocketUpgrade::max_write_buffer_size`
- **changed:** Deprecate `WebSocketUpgrade::max_send_queue`
- **change:** Update tokio-tungstenite to 0.20
- **added:** Implement `Handler` for `T: IntoResponse` ([#2140])

[#2140]: https://github.com/tokio-rs/axum/pull/2140

# 0.6.19 (17. July, 2023)

Expand Down
43 changes: 43 additions & 0 deletions axum/src/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,31 @@ pub use self::service::HandlerService;
/// {}
/// ```
#[doc = include_str!("../docs/debugging_handler_type_errors.md")]
///
/// # Handlers that aren't functions
///
/// The `Handler` trait is also implemented for `T: IntoResponse`. That allows easily returning
/// fixed data for routes:
///
/// ```
/// use axum::{
/// Router,
/// routing::{get, post},
/// Json,
/// http::StatusCode,
/// };
/// use serde_json::json;
///
/// let app = Router::new()
/// // respond with a fixed string
/// .route("/", get("Hello, World!"))
/// // or return some mock data
/// .route("/users", post((
/// StatusCode::CREATED,
/// Json(json!({ "id": 1, "username": "alice" })),
/// )));
/// # let _: Router = app;
/// ```
#[cfg_attr(
nightly_error_messages,
rustc_on_unimplemented(
Expand Down Expand Up @@ -231,6 +256,24 @@ macro_rules! impl_handler {

all_the_tuples!(impl_handler);

mod private {
// Marker type for `impl<T: IntoResponse> Handler for T`
#[allow(missing_debug_implementations)]
pub enum IntoResponseHandler {}
}

impl<T, S, B> Handler<private::IntoResponseHandler, S, B> for T
where
T: IntoResponse + Clone + Send + 'static,
B: Send + 'static,
{
type Future = std::future::Ready<Response>;

fn call(self, _req: Request<B>, _state: S) -> Self::Future {
std::future::ready(self.into_response())
}
}

/// A [`Service`] created from a [`Handler`] by applying a Tower middleware.
///
/// Created with [`Handler::layer`]. See that method for more details.
Expand Down
11 changes: 11 additions & 0 deletions axum/src/routing/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1026,3 +1026,14 @@ async fn connect_going_to_default_fallback() {
let body = hyper::body::to_bytes(res).await.unwrap();
assert!(body.is_empty());
}

#[crate::test]
async fn impl_handler_for_into_response() {
let app = Router::new().route("/things", post((StatusCode::CREATED, "thing created")));

let client = TestClient::new(app);

let res = client.post("/things").send().await;
assert_eq!(res.status(), StatusCode::CREATED);
assert_eq!(res.text().await, "thing created");
}

0 comments on commit 68333b2

Please sign in to comment.