Skip to content

Commit

Permalink
allow typed headers to be used for IntoResponse(Parts)
Browse files Browse the repository at this point in the history
  • Loading branch information
GlenDC committed Dec 22, 2024
1 parent f6a045a commit cb455e3
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 31 deletions.
11 changes: 4 additions & 7 deletions rama-http-types/src/response/form.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::fmt;

use crate::dep::http::header::CONTENT_TYPE;
use crate::dep::http::StatusCode;
use crate::dep::mime;
use crate::response::{IntoResponse, Response};
use crate::Body;
use headers::ContentType;
use rama_error::OpaqueError;
use rama_utils::macros::impl_deref;
use serde::Serialize;

use super::Headers;

/// Wrapper used to create Form Http [`Response`]s,
/// as well as to extract Form from Http [`Request`] bodies.
///
Expand Down Expand Up @@ -89,11 +90,7 @@ where
{
fn into_response(self) -> Response {
match serde_html_form::to_string(&self.0) {
Ok(body) => (
[(CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref())],
body,
)
.into_response(),
Ok(body) => (Headers::single(ContentType::form_url_encoded()), body).into_response(),
Err(err) => {
tracing::error!(error = %err, "response error");
StatusCode::INTERNAL_SERVER_ERROR.into_response()
Expand Down
60 changes: 60 additions & 0 deletions rama-http-types/src/response/headers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use super::{IntoResponse, IntoResponseParts, Response, ResponseParts};
use crate::headers::HeaderMapExt;

use headers::Header;
use rama_utils::macros::all_the_tuples_no_last_special_case;

/// Use typed [`Header`]s i a response.
pub struct Headers<T>(pub T);

impl<H: Header> Headers<(H,)> {
/// Create a Header singleton tuple.
pub fn single(h: H) -> Self {
Self((h,))
}
}

macro_rules! headers_into_response {
( $($ty:ident),* $(,)? ) => {
#[allow(non_snake_case)]
impl<$($ty),+> IntoResponse for Headers<($($ty),+,)>
where
$(
$ty: $crate::headers::Header,
)+
{
fn into_response(self) -> Response {
(self, ()).into_response()
}
}
}
}

all_the_tuples_no_last_special_case!(headers_into_response);

macro_rules! headers_into_response_parts {
( $($ty:ident),* $(,)? ) => {
#[allow(non_snake_case)]
impl<$($ty),+> IntoResponseParts for Headers<($($ty),+,)>
where
$(
$ty: $crate::headers::Header,
)+
{
type Error = std::convert::Infallible;

fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
let Headers((
$($ty),+
,
)) = self;
$(
res.headers_mut().typed_insert($ty);
)+
Ok(res)
}
}
}
}

all_the_tuples_no_last_special_case!(headers_into_response_parts);
14 changes: 5 additions & 9 deletions rama-http-types/src/response/html.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::{header, Body, HeaderValue, IntoResponse, Response};
use crate::{Body, IntoResponse, Response};
use headers::ContentType;
use rama_utils::macros::impl_deref;
use std::fmt;

use super::Headers;

/// An HTML response.
///
/// Will automatically get `Content-Type: text/html`.
Expand All @@ -26,14 +29,7 @@ where
T: Into<Body>,
{
fn into_response(self) -> Response {
(
[(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()),
)],
self.0.into(),
)
.into_response()
(Headers::single(ContentType::html()), self.0.into()).into_response()
}
}

Expand Down
21 changes: 6 additions & 15 deletions rama-http-types/src/response/json.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
use crate::response::{IntoResponse, Response};
use crate::{
dep::http::{
header::{self, HeaderValue},
StatusCode,
},
Body,
};
use crate::{dep::http::StatusCode, Body};
use bytes::{BufMut, BytesMut};
use headers::ContentType;
use rama_error::OpaqueError;
use rama_utils::macros::impl_deref;
use serde::Serialize;
use std::fmt;

use super::Headers;

/// Wrapper used to create Json Http [`Response`]s,
/// as well as to extract Json from Http [`Request`] bodies.
///
Expand Down Expand Up @@ -88,19 +85,13 @@ where
let mut buf = BytesMut::with_capacity(128).writer();
match serde_json::to_writer(&mut buf, &self.0) {
Ok(()) => (
[(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
)],
Headers::single(ContentType::json()),
buf.into_inner().freeze(),
)
.into_response(),
Err(err) => (
StatusCode::INTERNAL_SERVER_ERROR,
[(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
)],
Headers::single(ContentType::text_utf8()),
err.to_string(),
)
.into_response(),
Expand Down
2 changes: 2 additions & 0 deletions rama-http-types/src/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
use crate::Body;

mod append_headers;
mod headers;
mod into_response;
mod into_response_parts;

#[doc(inline)]
pub use self::{
append_headers::AppendHeaders,
headers::Headers,
into_response::{IntoResponse, StaticResponseFactory},
into_response_parts::{IntoResponseParts, ResponseParts, TryIntoHeaderError},
};
Expand Down

0 comments on commit cb455e3

Please sign in to comment.