Skip to main content

impulse_ui_kit/
router.rs

1//! Methods to work with routes.
2//!
3//! On the client (`csr`/`hydrate`) these helpers query the browser's
4//! `window.location`. On the server (`ssr`) they read from the per-request
5//! `impulse_ui_kit::ssr::RequestUrlCtx` context populated by the SSR handler.
6
7use impulse_utils::prelude::*;
8
9/// Get server's address and port.
10#[cfg(any(feature = "csr", feature = "hydrate"))]
11pub fn get_host() -> CResult<String> {
12  let server_host = web_sys::window()
13    .ok_or(ClientError::from_str("Can't get browser's window parameters."))?
14    .document()
15    .ok_or(ClientError::from_str("Can't get window's document."))?
16    .location()
17    .ok_or(ClientError::from_str("Can't get document's location."))?
18    .host()
19    .map_err(|e| ClientError::from_str(format!("Can't get host: {e:?}")))?
20    .to_string();
21  Ok(server_host)
22}
23
24/// Get server protocol (HTTP/HTTPS: "http:"/"https:").
25#[cfg(any(feature = "csr", feature = "hydrate"))]
26pub fn get_protocol() -> CResult<String> {
27  let server_proto = web_sys::window()
28    .ok_or(ClientError::from_str("Can't get browser's window parameters."))?
29    .document()
30    .ok_or(ClientError::from_str("Can't get window's document."))?
31    .location()
32    .ok_or(ClientError::from_str("Can't get document's location."))?
33    .protocol()
34    .map_err(|e| ClientError::from_str(format!("Can't get protocol: {e:?}")))?
35    .to_string();
36  Ok(server_proto)
37}
38
39/// Get path.
40#[cfg(any(feature = "csr", feature = "hydrate"))]
41pub fn get_path() -> CResult<String> {
42  let path = web_sys::window()
43    .ok_or(ClientError::from_str("Can't get browser's window parameters."))?
44    .document()
45    .ok_or(ClientError::from_str("Can't get window's document."))?
46    .location()
47    .ok_or(ClientError::from_str("Can't get document's location."))?
48    .pathname()
49    .map_err(|e| ClientError::from_str(format!("Can't get pathname: {e:?}")))?
50    .to_string();
51  Ok(path)
52}
53
54/// Redirect to any URL.
55#[cfg(any(feature = "csr", feature = "hydrate"))]
56pub fn redirect(url: impl AsRef<str>) -> CResult<()> {
57  web_sys::window()
58    .ok_or(ClientError::from_str("Can't get browser's window parameters."))?
59    .document()
60    .ok_or(ClientError::from_str("Can't get window's document."))?
61    .location()
62    .ok_or(ClientError::from_str("Can't get document's location."))?
63    .set_href(url.as_ref())
64    .map_err(|e| ClientError::from_str(format!("Can't redirect: {e:?}")))
65}
66
67/// Get endpoint to your backend server.
68///
69/// Example:
70///
71/// ```rust,ignore
72/// use impulse_ui_kit::router::endpoint;
73///
74/// fn main() {
75///   // Let assume that your backend is located at `127.0.0.1:8080` with HTTP schema
76///   assert_eq!(endpoint("/some/api/route").as_str(), "http://127.0.0.1:8080/some/api/route");
77/// }
78/// ```
79#[cfg(any(feature = "csr", feature = "hydrate"))]
80pub fn endpoint(api_uri: impl AsRef<str>) -> String {
81  format!(
82    "{}//{}{}",
83    get_protocol().unwrap(),
84    get_host().unwrap(),
85    api_uri.as_ref()
86  )
87}
88
89/// Get server's host (e.g. "127.0.0.1:8801") from the per-request SSR context.
90#[cfg(feature = "ssr")]
91pub fn get_host() -> CResult<String> {
92  use leptos::context::use_context;
93  let ctx = use_context::<crate::ssr::RequestUrlCtx>()
94    .ok_or(ClientError::from_str("RequestUrlCtx not provided in SSR context"))?;
95  Ok(ctx.host)
96}
97
98/// Get protocol scheme with trailing colon ("http:" / "https:") from the SSR context.
99#[cfg(feature = "ssr")]
100pub fn get_protocol() -> CResult<String> {
101  use leptos::context::use_context;
102  let ctx = use_context::<crate::ssr::RequestUrlCtx>()
103    .ok_or(ClientError::from_str("RequestUrlCtx not provided in SSR context"))?;
104  Ok(format!("{}:", ctx.scheme))
105}
106
107/// Get the requested path from the SSR context.
108#[cfg(feature = "ssr")]
109pub fn get_path() -> CResult<String> {
110  use leptos::context::use_context;
111  let ctx = use_context::<crate::ssr::RequestUrlCtx>()
112    .ok_or(ClientError::from_str("RequestUrlCtx not provided in SSR context"))?;
113  Ok(ctx.path)
114}
115
116/// On SSR, "redirect" stores the redirect target on [`crate::ssr::LeptosResponseOptions`].
117/// The SSR handler reads it after rendering and short-circuits the response.
118#[cfg(feature = "ssr")]
119pub fn redirect(url: impl AsRef<str>) -> CResult<()> {
120  use leptos::context::use_context;
121  let opts = use_context::<crate::ssr::LeptosResponseOptions>().ok_or(ClientError::from_str(
122    "LeptosResponseOptions not provided in SSR context",
123  ))?;
124  opts.set_redirect(url.as_ref().to_string());
125  Ok(())
126}
127
128/// Get endpoint to your backend server (SSR variant).
129#[cfg(feature = "ssr")]
130pub fn endpoint(api_uri: impl AsRef<str>) -> String {
131  format!(
132    "{}//{}{}",
133    get_protocol().unwrap_or_else(|_| "http:".to_string()),
134    get_host().unwrap_or_default(),
135    api_uri.as_ref()
136  )
137}