Remove Uri from responders - replace with String (#32)

* remove `Uri` from responders - replace with `String`

* clean clippy warnings
This commit is contained in:
Dmitry Kudryavtsev 2025-06-03 20:49:41 +02:00 committed by GitHub
parent 8e4e2126ba
commit 4eae8b3fe2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 102 deletions

View file

@ -65,11 +65,11 @@ any of your responses.
| Header | Responder | Value |
|---------------------------|---------------------|-------------------------------------|
| `HX-Location` | `HxLocation` | `axum::http::Uri` |
| `HX-Push-Url` | `HxPushUrl` | `axum::http::Uri` |
| `HX-Redirect` | `HxRedirect` | `axum::http::Uri` |
| `HX-Location` | `HxLocation` | `String` |
| `HX-Push-Url` | `HxPushUrl` | `String` |
| `HX-Redirect` | `HxRedirect` | `String` |
| `HX-Refresh` | `HxRefresh` | `bool` |
| `HX-Replace-Url` | `HxReplaceUrl` | `axum::http::Uri` |
| `HX-Replace-Url` | `HxReplaceUrl` | `String` |
| `HX-Reswap` | `HxReswap` | `axum_htmx::responders::SwapOption` |
| `HX-Retarget` | `HxRetarget` | `String` |
| `HX-Reselect` | `HxReselect` | `String` |

View file

@ -1,9 +1,9 @@
//! Axum responses for htmx response headers.
use std::{convert::Infallible, str::FromStr};
use std::convert::Infallible;
use axum_core::response::{IntoResponseParts, ResponseParts};
use http::{HeaderValue, Uri};
use http::HeaderValue;
use crate::{headers, HxError};
@ -32,7 +32,7 @@ const HX_SWAP_NONE: &str = "none";
///
/// See <https://htmx.org/headers/hx-push-url/> for more information.
#[derive(Debug, Clone)]
pub struct HxPushUrl(pub Uri);
pub struct HxPushUrl(pub String);
impl IntoResponseParts for HxPushUrl {
type Error = HxError;
@ -40,24 +40,16 @@ impl IntoResponseParts for HxPushUrl {
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut().insert(
headers::HX_PUSH_URL,
HeaderValue::from_maybe_shared(self.0.to_string())?,
HeaderValue::from_maybe_shared(self.0)?,
);
Ok(res)
}
}
impl From<Uri> for HxPushUrl {
fn from(uri: Uri) -> Self {
Self(uri)
}
}
impl<'a> TryFrom<&'a str> for HxPushUrl {
type Error = <Uri as FromStr>::Err;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
Ok(Self(value.parse()?))
impl<'a> From<&'a str> for HxPushUrl {
fn from(value: &'a str) -> Self {
Self(value.to_string())
}
}
@ -68,7 +60,7 @@ impl<'a> TryFrom<&'a str> for HxPushUrl {
/// Will fail if the supplied Uri contains characters that are not visible ASCII
/// (32-127).
#[derive(Debug, Clone)]
pub struct HxRedirect(pub Uri);
pub struct HxRedirect(pub String);
impl IntoResponseParts for HxRedirect {
type Error = HxError;
@ -76,24 +68,16 @@ impl IntoResponseParts for HxRedirect {
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut().insert(
headers::HX_REDIRECT,
HeaderValue::from_maybe_shared(self.0.to_string())?,
HeaderValue::from_maybe_shared(self.0)?,
);
Ok(res)
}
}
impl From<Uri> for HxRedirect {
fn from(uri: Uri) -> Self {
Self(uri)
}
}
impl<'a> TryFrom<&'a str> for HxRedirect {
type Error = <Uri as FromStr>::Err;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
Ok(Self(value.parse()?))
impl<'a> From<&'a str> for HxRedirect {
fn from(value: &'a str) -> Self {
Self(value.to_string())
}
}
@ -137,7 +121,7 @@ impl IntoResponseParts for HxRefresh {
///
/// See <https://htmx.org/headers/hx-replace-url/> for more information.
#[derive(Debug, Clone)]
pub struct HxReplaceUrl(pub Uri);
pub struct HxReplaceUrl(pub String);
impl IntoResponseParts for HxReplaceUrl {
type Error = HxError;
@ -145,24 +129,16 @@ impl IntoResponseParts for HxReplaceUrl {
fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
res.headers_mut().insert(
headers::HX_REPLACE_URL,
HeaderValue::from_maybe_shared(self.0.to_string())?,
HeaderValue::from_maybe_shared(self.0)?,
);
Ok(res)
}
}
impl From<Uri> for HxReplaceUrl {
fn from(uri: Uri) -> Self {
Self(uri)
}
}
impl<'a> TryFrom<&'a str> for HxReplaceUrl {
type Error = <Uri as FromStr>::Err;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
Ok(Self(value.parse()?))
impl<'a> From<&'a str> for HxReplaceUrl {
fn from(value: &'a str) -> Self {
Self(value.to_string())
}
}

View file

@ -1,7 +1,5 @@
use std::str::FromStr;
use axum_core::response::{IntoResponseParts, ResponseParts};
use http::{HeaderValue, Uri};
use http::HeaderValue;
use crate::{headers, HxError};
@ -12,14 +10,14 @@ use crate::{headers, HxError};
/// target on the page, you must enable the `serde` feature flag and specify
/// [`LocationOptions`].
///
/// Will fail if the supplied Uri contains characters that are not visible ASCII
/// Will fail if the supplied uri contains characters that are not visible ASCII
/// (32-127).
///
/// See <https://htmx.org/headers/hx-location/> for more information.
#[derive(Debug, Clone)]
pub struct HxLocation {
/// Uri of the new location.
pub uri: Uri,
pub uri: String,
/// Extra options.
#[cfg(feature = "serde")]
#[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
@ -27,43 +25,24 @@ pub struct HxLocation {
}
impl HxLocation {
/// Creates location from [`Uri`] without any options.
pub fn from_uri(uri: Uri) -> Self {
/// Parses `uri` and sets it as location.
#[allow(clippy::should_implement_trait)]
pub fn from_str(uri: impl AsRef<str>) -> Self {
Self {
#[cfg(feature = "serde")]
options: LocationOptions::default(),
uri,
uri: uri.as_ref().to_string(),
}
}
/// Creates location from [`Uri`] and options.
#[cfg(feature = "serde")]
#[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
pub fn from_uri_with_options(uri: Uri, options: LocationOptions) -> Self {
Self { uri, options }
}
/// Parses `uri` and sets it as location.
#[allow(clippy::should_implement_trait)]
pub fn from_str(uri: impl AsRef<str>) -> Result<Self, http::uri::InvalidUri> {
Ok(Self {
#[cfg(feature = "serde")]
options: LocationOptions::default(),
uri: uri.as_ref().parse::<Uri>()?,
})
}
/// Parses `uri` and sets it as location with additional options.
#[cfg(feature = "serde")]
#[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
pub fn from_str_with_options(
uri: impl AsRef<str>,
options: LocationOptions,
) -> Result<Self, http::uri::InvalidUri> {
Ok(Self {
pub fn from_str_with_options(uri: impl AsRef<str>, options: LocationOptions) -> Self {
Self {
options,
uri: uri.as_ref().parse::<Uri>()?,
})
uri: uri.as_ref().to_string(),
}
}
#[cfg(feature = "serde")]
@ -88,34 +67,16 @@ impl HxLocation {
}
}
impl From<Uri> for HxLocation {
fn from(uri: Uri) -> Self {
Self::from_uri(uri)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
impl From<(Uri, LocationOptions)> for HxLocation {
fn from((uri, options): (Uri, LocationOptions)) -> Self {
Self::from_uri_with_options(uri, options)
}
}
impl<'a> TryFrom<&'a str> for HxLocation {
type Error = <Uri as FromStr>::Err;
fn try_from(uri: &'a str) -> Result<Self, Self::Error> {
impl<'a> From<&'a str> for HxLocation {
fn from(uri: &'a str) -> Self {
Self::from_str(uri)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))]
impl<'a> TryFrom<(&'a str, LocationOptions)> for HxLocation {
type Error = <Uri as FromStr>::Err;
fn try_from((uri, options): (&'a str, LocationOptions)) -> Result<Self, Self::Error> {
impl<'a> From<(&'a str, LocationOptions)> for HxLocation {
fn from((uri, options): (&'a str, LocationOptions)) -> Self {
Self::from_str_with_options(uri, options)
}
}
@ -207,11 +168,11 @@ mod tests {
fn test_serialize_location() {
use crate::SwapOption;
let loc = HxLocation::try_from("/foo").unwrap();
let loc = HxLocation::from("/foo");
assert_eq!(loc.into_header_with_options().unwrap(), "/foo");
let loc = HxLocation::from_uri_with_options(
"/foo".parse().unwrap(),
let loc = HxLocation::from_str_with_options(
"/foo",
LocationOptions {
event: Some("click".into()),
swap: Some(SwapOption::InnerHtml),