Update integration with support for axum 0.7 (#2082)

* chore: update to axum 0.7

Removed http, since it's included in axum, and replaced hyper by http-body-util, which is a smaller.

* chore: update samples to work with nre axum

Missing sessions_axum_auth, pending PR merge.

* chore: all dependencies update to axum 0.7

* chore: cargo fmt

* chore: fix doctests

* chore: Fix example that in reality doesn't use axum.

Fixed anyway.

* chore: more examples support for axum 0.7

* Small tweak
This commit is contained in:
Daniel Santana 2023-12-31 00:05:17 +00:00 committed by Greg Johnston
parent 0c4cf5471d
commit cadd217078
32 changed files with 233 additions and 265 deletions

View file

@ -7,22 +7,22 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_log = "1.0.0"
console_error_panic_hook = "0.1.7"
cfg-if = "1.0.0"
console_log = "1.0"
console_error_panic_hook = "0.1"
cfg-if = "1.0"
leptos = { path = "../../leptos", features = ["nightly"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta" }
leptos_router = { path = "../../router" }
log = "0.4.17"
log = "0.4"
serde = { version = "1", features = ["derive"] }
simple_logger = "4.0.0"
axum = { version = "0.6.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
tokio = { version = "1.22.0", features = ["full"], optional = true }
http = { version = "0.2.8" }
thiserror = "1.0.38"
simple_logger = "4.0"
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0" }
thiserror = "1.0"
wasm-bindgen = "0.2"
[features]

View file

@ -2,7 +2,7 @@ use cfg_if::cfg_if;
cfg_if! { if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::{Body},
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -28,12 +28,12 @@ cfg_if! { if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),

View file

@ -61,8 +61,8 @@ async fn main() {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
log!("listening on http://{}", &addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -11,24 +11,24 @@ codegen-units = 1
lto = true
[dependencies]
console_log = "1.0.0"
console_error_panic_hook = "0.1.7"
cfg-if = "1.0.0"
console_log = "1.0"
console_error_panic_hook = "0.1"
cfg-if = "1.0"
leptos = { path = "../../leptos", features = ["nightly"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4.17"
simple_logger = "4.0.0"
serde = { version = "1.0.148", features = ["derive"] }
log = "0.4"
simple_logger = "4.0"
serde = { version = "1.0", features = ["derive"] }
tracing = "0.1"
gloo-net = { version = "0.2.5", features = ["http"] }
reqwest = { version = "0.11.13", features = ["json"] }
axum = { version = "0.6.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
tokio = { version = "1.22.0", features = ["full"], optional = true }
http = { version = "0.2.11", optional = true }
gloo-net = { version = "0.4", features = ["http"] }
reqwest = { version = "0.11", features = ["json"] }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0", optional = true }
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
wasm-bindgen = "0.2"

View file

@ -3,7 +3,7 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -26,12 +26,12 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", err),

View file

@ -3,13 +3,14 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
http::{Request, Response, StatusCode, Uri},
response::IntoResponse,
};
use tower::ServiceExt;
use tower_http::services::ServeDir;
pub async fn file_handler(uri: Uri) -> Result<Response<BoxBody>, (StatusCode, String)> {
pub async fn file_handler(uri: Uri) -> Result<Response<Body>, (StatusCode, String)> {
let res = get_static_file(uri.clone(), "/pkg").await?;
if res.status() == StatusCode::NOT_FOUND {
@ -24,7 +25,7 @@ if #[cfg(feature = "ssr")] {
}
}
pub async fn get_static_file_handler(uri: Uri) -> Result<Response<BoxBody>, (StatusCode, String)> {
pub async fn get_static_file_handler(uri: Uri) -> Result<Response<Body>, (StatusCode, String)> {
let res = get_static_file(uri.clone(), "/static").await?;
if res.status() == StatusCode::NOT_FOUND {
@ -34,14 +35,14 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, base: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, base: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(&uri).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// When run normally, the root should be the crate root
if base == "/static" {
match ServeDir::new("./static").oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", err),
@ -49,7 +50,7 @@ if #[cfg(feature = "ssr")] {
}
} else if base == "/pkg" {
match ServeDir::new("./pkg").oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", err),

View file

@ -32,8 +32,8 @@ if #[cfg(feature = "ssr")] {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
log!("listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -11,9 +11,9 @@ codegen-units = 1
lto = true
[dependencies]
console_log = "1.0.0"
console_error_panic_hook = "0.1.7"
cfg-if = "1.0.0"
console_log = "1.0"
console_error_panic_hook = "0.1"
cfg-if = "1.0"
leptos = { path = "../../leptos", features = [
"nightly",
"experimental-islands",
@ -23,20 +23,20 @@ leptos_axum = { path = "../../integrations/axum", optional = true, features = [
] }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4.17"
simple_logger = "4.0.0"
serde = { version = "1.0.148", features = ["derive"] }
log = "0.4"
simple_logger = "4.0"
serde = { version = "1.0", features = ["derive"] }
tracing = "0.1"
gloo-net = { version = "0.2.5", features = ["http"] }
reqwest = { version = "0.11.13", features = ["json"] }
axum = { version = "0.6.1", optional = true, features = ["http2"] }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = [
gloo-net = { version = "0.4", features = ["http"] }
reqwest = { version = "0.11", features = ["json"] }
axum = { version = "0.7", optional = true, features = ["http2"] }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = [
"fs",
"compression-br",
], optional = true }
tokio = { version = "1.22.0", features = ["full"], optional = true }
http = { version = "0.2.11", optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0", optional = true }
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
wasm-bindgen = "0.2"
lazy_static = "1.4.0"

View file

@ -3,7 +3,7 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -26,12 +26,12 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", err),

View file

@ -3,13 +3,13 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
http::{Request, Response, StatusCode, Uri},
};
use tower::ServiceExt;
use tower_http::services::ServeDir;
pub async fn file_handler(uri: Uri) -> Result<Response<BoxBody>, (StatusCode, String)> {
pub async fn file_handler(uri: Uri) -> Result<Response<Body>, (StatusCode, String)> {
let res = get_static_file(uri.clone(), "/pkg").await?;
if res.status() == StatusCode::NOT_FOUND {
@ -24,7 +24,7 @@ if #[cfg(feature = "ssr")] {
}
}
pub async fn get_static_file_handler(uri: Uri) -> Result<Response<BoxBody>, (StatusCode, String)> {
pub async fn get_static_file_handler(uri: Uri) -> Result<Response<Body>, (StatusCode, String)> {
let res = get_static_file(uri.clone(), "/static").await?;
if res.status() == StatusCode::NOT_FOUND {
@ -34,14 +34,14 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, base: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, base: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(&uri).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// When run normally, the root should be the crate root
if base == "/static" {
match ServeDir::new("./static").oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", err),
@ -49,7 +49,7 @@ if #[cfg(feature = "ssr")] {
}
} else if base == "/pkg" {
match ServeDir::new("./pkg").oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", err),

View file

@ -27,8 +27,8 @@ async fn main() {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
logging::log!("listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -11,22 +11,22 @@ codegen-units = 1
lto = true
[dependencies]
console_log = "1.0.0"
console_error_panic_hook = "0.1.7"
cfg-if = "1.0.0"
console_log = "1.0"
console_error_panic_hook = "0.1"
cfg-if = "1.0"
leptos = { path = "../../leptos", features = ["nightly"] }
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4.17"
simple_logger = "4.0.0"
serde = { version = "1.0.148", features = ["derive"] }
log = "0.4"
simple_logger = "4.0"
serde = { version = "1.0", features = ["derive"] }
tracing = "0.1"
gloo-net = { version = "0.4.0", features = ["http"] }
reqwest = { version = "0.11.13", features = ["json"] }
axum = { version = "0.6", default-features = false, optional = true }
tower = { version = "0.4.13", optional = true }
http = { version = "0.2.11", optional = true }
gloo-net = { version = "0.4", features = ["http"] }
reqwest = { version = "0.11", features = ["json"] }
axum = { version = "0.7", default-features = false, optional = true }
tower = { version = "0.4", optional = true }
http = { version = "1.0", optional = true }
web-sys = { version = "0.3", features = [
"AbortController",
"AbortSignal",
@ -34,10 +34,10 @@ web-sys = { version = "0.3", features = [
"Response",
] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = { version = "0.4.37", features = [
wasm-bindgen-futures = { version = "0.4", features = [
"futures-core-03-stream",
], optional = true }
axum-js-fetch = { version = "0.2.1", optional = true }
axum-js-fetch = { version = "0.2", optional = true }
lazy_static = "1.4.0"
[features]

View file

@ -3,7 +3,7 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -25,7 +25,7 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root

View file

@ -62,7 +62,7 @@ cfg_if! {
let routes = generate_route_list(App);
// build our application with a route
let app: axum::Router<(), axum::body::Body> = Router::new()
let app: axum::Router = Router::new()
.leptos_routes(&leptos_options, routes, || view! { <App/> } )
.route("/api/*fn_name", post(leptos_axum::handle_server_fns))
.with_state(leptos_options);

View file

@ -7,40 +7,41 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
anyhow = "1.0.66"
console_log = "1.0.0"
rand = { version = "0.8.5", features = ["min_const_gen"], optional = true }
console_error_panic_hook = "0.1.7"
futures = "0.3.25"
cfg-if = "1.0.0"
anyhow = "1.0"
console_log = "1.0"
rand = { version = "0.8", features = ["min_const_gen"], optional = true }
console_error_panic_hook = "0.1"
futures = "0.3"
cfg-if = "1.0"
leptos = { path = "../../leptos", features = ["nightly"] }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4.17"
simple_logger = "4.0.0"
serde = { version = "1.0.148", features = ["derive"] }
axum = { version = "0.6.1", optional = true, features=["macros"] }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
tokio = { version = "1.22.0", features = ["full"], optional = true }
http = { version = "0.2.11" }
log = "0.4"
simple_logger = "4.0"
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7", optional = true, features=["macros"] }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0" }
sqlx = { version = "0.7.2", features = [
"runtime-tokio-rustls",
"sqlite",
], optional = true }
thiserror = "1.0.38"
thiserror = "1.0"
wasm-bindgen = "0.2"
axum_session_auth = { version = "0.9.0", features = [
axum_session_auth = { version = "0.10", features = [
"sqlite-rustls",
], optional = true }
axum_session = { version = "0.9.0", features = [
axum_session = { version = "0.10", features = [
"sqlite-rustls",
], optional = true }
bcrypt = { version = "0.14", optional = true }
async-trait = { version = "0.1.64", optional = true }
bcrypt = { version = "0.15", optional = true }
async-trait = { version = "0.1", optional = true }
[features]
default = ["ssr"]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = [
"dep:axum",

View file

@ -3,7 +3,7 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -29,12 +29,12 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),

View file

@ -100,8 +100,8 @@ if #[cfg(feature = "ssr")] {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
log!("listening on http://{}", &addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -18,9 +18,9 @@ leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4"
serde = { version = "1", features = ["derive"] }
thiserror = "1"
axum = { version = "0.6.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["time"], optional = true }
wasm-bindgen = "0.2"

View file

@ -2,7 +2,7 @@ use cfg_if::cfg_if;
cfg_if! { if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -28,12 +28,12 @@ cfg_if! { if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),

View file

@ -27,8 +27,8 @@ async fn main() {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
log!("listening on http://{}", &addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -7,8 +7,8 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
axum = { version = "0.6.18", optional = true }
console_error_panic_hook = "0.1.7"
axum = { version = "0.7", optional = true }
console_error_panic_hook = "0.1"
console_log = "1"
cfg-if = "1"
leptos = { path = "../../leptos", features = ["nightly"] }
@ -17,13 +17,13 @@ leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4.17"
simple_logger = "4"
tokio = { version = "1.28.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
wasm-bindgen = "0.2.84"
thiserror = "1.0.40"
tracing = { version = "0.1.37", optional = true }
http = "0.2.11"
tokio = { version = "1", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
wasm-bindgen = "0.2"
thiserror = "1.0"
tracing = { version = "0.1", optional = true }
http = "1.0"
[features]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]

View file

@ -2,7 +2,7 @@ use cfg_if::cfg_if;
cfg_if! { if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -28,12 +28,12 @@ cfg_if! { if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),

View file

@ -31,8 +31,8 @@ async fn main() {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
info!("listening on http://{}", &addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -7,27 +7,27 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_log = "1.0.0"
console_error_panic_hook = "0.1.7"
futures = "0.3.25"
cfg-if = "1.0.0"
console_log = "1.0"
console_error_panic_hook = "0.1"
futures = "0.3"
cfg-if = "1.0"
http = "1.0"
leptos = { path = "../../leptos", features = ["nightly"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_router = { path = "../../router", features = ["nightly"] }
log = "0.4.17"
simple_logger = "4.0.0"
log = "0.4"
simple_logger = "4.0"
serde = { version = "1", features = ["derive"] }
axum = { version = "0.6.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
tokio = { version = "1.22.0", features = ["full"], optional = true }
http = { version = "0.2.11" }
sqlx = { version = "0.6.2", features = [
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
sqlx = { version = "0.7", features = [
"runtime-tokio-rustls",
"sqlite",
], optional = true }
thiserror = "1.0.38"
thiserror = "1.0"
wasm-bindgen = "0.2"
[features]

View file

@ -3,7 +3,7 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
@ -29,12 +29,12 @@ if #[cfg(feature = "ssr")] {
}
}
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),

View file

@ -10,14 +10,14 @@ cfg_if! {
response::{IntoResponse, Response},
Router,
};
use axum::body::Body as AxumBody;
use axum::body::Body;
use crate::todo::*;
use todo_app_sqlite_axum::*;
use crate::fallback::file_and_error_handler;
use leptos_axum::{generate_route_list, LeptosRoutes};
//Define a handler to test extractor with state
async fn custom_handler(Path(id): Path<String>, State(options): State<LeptosOptions>, req: Request<AxumBody>) -> Response{
async fn custom_handler(Path(id): Path<String>, State(options): State<LeptosOptions>, req: Request<Body>) -> Response{
let handler = leptos_axum::render_app_to_stream_with_context(options,
move || {
provide_context(id.clone());
@ -60,9 +60,9 @@ cfg_if! {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
logging::log!("listening on http://{}", &addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -7,27 +7,27 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_log = "1.0.0"
console_error_panic_hook = "0.1.7"
futures = "0.3.25"
console_log = "1.0"
console_error_panic_hook = "0.1"
futures = "0.3"
leptos = { path = "../../leptos", features = ["nightly"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta", features = ["nightly"] }
leptos_router = { path = "../../router", features = ["nightly"] }
leptos_integration_utils = { path = "../../integrations/utils", optional = true }
log = "0.4.17"
simple_logger = "4.0.0"
log = "0.4"
simple_logger = "4.0"
serde = { version = "1", features = ["derive"] }
axum = { version = "0.6.1", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.4", features = ["fs"], optional = true }
tokio = { version = "1.22.0", features = ["full"], optional = true }
http = { version = "0.2.11" }
sqlx = { version = "0.6.2", features = [
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0" }
sqlx = { version = "0.7", features = [
"runtime-tokio-rustls",
"sqlite",
], optional = true }
thiserror = "1.0.38"
thiserror = "1.0"
wasm-bindgen = "0.2"
[features]

View file

@ -1,5 +1,5 @@
use axum::{
body::{boxed, Body, BoxBody},
body::Body,
extract::State,
http::{Request, Response, StatusCode, Uri},
response::{Html, IntoResponse, Response as AxumResponse},
@ -28,7 +28,7 @@ pub async fn file_or_index_handler(
async fn get_static_file(
uri: Uri,
root: &str,
) -> Result<Response<BoxBody>, (StatusCode, String)> {
) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder()
.uri(uri.clone())
.body(Body::empty())
@ -36,7 +36,7 @@ async fn get_static_file(
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),

View file

@ -39,8 +39,10 @@ async fn main() {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
logging::log!("listening on http://{}", &addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
let listener = tokio::net::TcpListener::bind(&addr)
.await
.expect("couldn't bind to address");
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}

View file

@ -8,23 +8,26 @@ repository = "https://github.com/leptos-rs/leptos"
description = "Axum integrations for the Leptos web framework."
[dependencies]
axum = { version = "0.6", default-features = false, features = [
axum = { version = "0.7", default-features = false, features = [
"matched-path",
] }
futures = "0.3"
http = "0.2.11"
hyper = "0.14.23"
http-body-util = "0.1"
leptos = { workspace = true, features = ["ssr"] }
leptos_meta = { workspace = true, features = ["ssr"] }
leptos_router = { workspace = true, features = ["ssr"] }
leptos_integration_utils = { workspace = true }
parking_lot = "0.12"
serde_json = "1"
tokio = { version = "1", default-features = false }
parking_lot = "0.12.1"
tokio-util = { version = "0.7.7", features = ["rt"] }
tracing = "0.1.37"
once_cell = "1.17"
cfg-if = "1.0.0"
tokio-util = { version = "0.7", features = ["rt"] }
tracing = "0.1"
once_cell = "1.18"
cfg-if = "1.0"
[dev-dependencies]
axum = "0.7"
tokio = { version = "1", features = ["net"] }
[features]
nonce = ["leptos/nonce"]

View file

@ -34,11 +34,15 @@
//! directory in the Leptos repository.
use axum::{
body::{Body, Bytes, Full, StreamBody},
body::{Body, Bytes},
extract::{FromRef, FromRequestParts, MatchedPath, Path, RawQuery},
http::{
header::{HeaderName, HeaderValue},
HeaderMap, Request, StatusCode,
header::{self, HeaderName, HeaderValue},
method::Method,
request::Parts,
uri::Uri,
version::Version,
HeaderMap, Request, Response, StatusCode,
},
response::IntoResponse,
routing::{delete, get, patch, post, put},
@ -47,11 +51,7 @@ use futures::{
channel::mpsc::{Receiver, Sender},
Future, SinkExt, Stream, StreamExt,
};
use http::{
header, method::Method, request::Parts, uri::Uri, version::Version,
Response,
};
use hyper::body;
use http_body_util::BodyExt;
use leptos::{
leptos_server::{server_fn_by_path, Payload},
server_fn::Encoding,
@ -162,7 +162,7 @@ pub async fn generate_request_and_parts(
) -> (Request<Body>, RequestParts) {
// provide request headers as context in server scope
let (parts, body) = req.into_parts();
let body = body::to_bytes(body).await.unwrap_or_default();
let body = body.collect().await.unwrap_or_default().to_bytes();
let request_parts = RequestParts {
method: parts.method.clone(),
uri: parts.uri.clone(),
@ -196,9 +196,8 @@ pub async fn generate_request_and_parts(
/// .route("/api/*fn_name", post(leptos_axum::handle_server_fns));
///
/// // run our app with hyper
/// // `axum::Server` is a re-export of `hyper::Server`
/// axum::Server::bind(&addr)
/// .serve(app.into_make_service())
/// let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
/// axum::serve(listener, app.into_make_service())
/// .await
/// .unwrap();
/// }
@ -358,21 +357,21 @@ async fn handle_server_fns_inner(
match serialized {
Payload::Binary(data) => res
.header("Content-Type", "application/cbor")
.body(Full::from(data)),
.body(Body::from(data)),
Payload::Url(data) => res
.header(
"Content-Type",
"application/x-www-form-urlencoded",
)
.body(Full::from(data)),
.body(Body::from(data)),
Payload::Json(data) => res
.header("Content-Type", "application/json")
.body(Full::from(data)),
.body(Body::from(data)),
}
}
Err(e) => Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Full::from(
.body(Body::from(
serde_json::to_string(&e)
.unwrap_or_else(|_| e.to_string()),
)),
@ -382,7 +381,7 @@ async fn handle_server_fns_inner(
res
} else {
Response::builder().status(StatusCode::BAD_REQUEST).body(
Full::from(format!(
Body::from(format!(
"Could not find a server function at the route \
{fn_name}. \n\nIt's likely that either
1. The API prefix you specify in the `#[server]` \
@ -442,9 +441,8 @@ pub type PinnedHtmlStream =
/// ));
///
/// // run our app with hyper
/// // `axum::Server` is a re-export of `hyper::Server`
/// axum::Server::bind(&addr)
/// .serve(app.into_make_service())
/// let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
/// axum::serve(listener, app.into_make_service())
/// .await
/// .unwrap();
/// }
@ -463,13 +461,8 @@ pub fn render_app_to_stream<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -490,13 +483,8 @@ pub fn render_route<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -504,6 +492,7 @@ where
{
render_route_with_context(options, paths, || {}, app_fn)
}
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], serving an in-order HTML stream of your application.
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve before
@ -543,9 +532,8 @@ where
/// ));
///
/// // run our app with hyper
/// // `axum::Server` is a re-export of `hyper::Server`
/// axum::Server::bind(&addr)
/// .serve(app.into_make_service())
/// let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
/// axum::serve(listener, app.into_make_service())
/// .await
/// .unwrap();
/// }
@ -564,13 +552,8 @@ pub fn render_app_to_stream_in_order<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -611,13 +594,8 @@ pub fn render_app_to_stream_with_context<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -644,13 +622,8 @@ pub fn render_route_with_context<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -704,6 +677,7 @@ where
}
}
}
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], serving an HTML stream of your application.
///
@ -732,13 +706,8 @@ pub fn render_app_to_stream_with_context_and_replace_blocks<IV>(
replace_blocks: bool,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -791,7 +760,7 @@ where
async fn generate_response(
res_options: ResponseOptions,
rx: Receiver<String>,
) -> Response<StreamBody<PinnedHtmlStream>> {
) -> Response<Body> {
let mut stream = Box::pin(rx.map(|html| Ok(Bytes::from(html))));
// Get the first and second chunks in the stream, which renders the app shell, and thus allows Resources to run
@ -806,9 +775,9 @@ async fn generate_response(
futures::stream::iter([first_chunk.unwrap(), second_chunk.unwrap()])
.chain(stream);
let mut res = Response::new(StreamBody::new(
Box::pin(complete_stream) as PinnedHtmlStream
));
let mut res =
Body::from_stream(Box::pin(complete_stream) as PinnedHtmlStream)
.into_response();
if let Some(status) = res_options.status {
*res.status_mut() = status
@ -819,11 +788,11 @@ async fn generate_response(
let mut res_headers = res_options.headers.clone();
headers.extend(res_headers.drain());
if !headers.contains_key(http::header::CONTENT_TYPE) {
if !headers.contains_key(header::CONTENT_TYPE) {
// Set the Content Type headers on all responses. This makes Firefox show the page source
// without complaining
headers.insert(
http::header::CONTENT_TYPE,
header::CONTENT_TYPE,
HeaderValue::from_str("text/html; charset=utf-8").unwrap(),
);
}
@ -897,13 +866,8 @@ pub fn render_app_to_stream_in_order_with_context<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -1012,8 +976,9 @@ fn provide_contexts(
///
/// // run our app with hyper
/// // `axum::Server` is a re-export of `hyper::Server`
/// axum::Server::bind(&addr)
/// .serve(app.into_make_service())
/// let listener =
/// tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
/// axum::serve(listener, app.into_make_service())
/// .await
/// .unwrap();
/// }
@ -1075,13 +1040,8 @@ pub fn render_app_async_stream_with_context<IV>(
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
) -> Pin<
Box<
dyn Future<Output = Response<StreamBody<PinnedHtmlStream>>>
+ Send
+ 'static,
>,
> + Clone
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
where
@ -1149,10 +1109,10 @@ where
let complete_stream =
futures::stream::iter([Ok(Bytes::from(html))]);
let mut res = Response::new(StreamBody::new(Box::pin(
complete_stream,
let mut res = Body::from_stream(
Box::pin(complete_stream) as PinnedHtmlStream
)
as PinnedHtmlStream));
.into_response();
if let Some(status) = res_options.status {
*res.status_mut() = status
}
@ -1162,11 +1122,11 @@ where
headers.extend(res_headers.drain());
// This one doesn't use generate_response(), so we need to do this seperately
if !headers.contains_key(http::header::CONTENT_TYPE) {
if !headers.contains_key(header::CONTENT_TYPE) {
// Set the Content Type headers on all responses. This makes Firefox show the page source
// without complaining
headers.insert(
http::header::CONTENT_TYPE,
header::CONTENT_TYPE,
HeaderValue::from_str("text/html; charset=utf-8")
.unwrap(),
);
@ -1291,6 +1251,7 @@ where
})
}
}
/// Generates a list of all routes defined in Leptos's Router in your app. We can then use this to automatically
/// create routes in Axum's Router without having to use wildcard matching or fallbacks. Takes in your root app Element
/// as an argument so it can walk you app tree. This version is tailored to generate Axum compatible paths.
@ -1464,7 +1425,7 @@ where
handler: H,
) -> Self
where
H: axum::handler::Handler<T, S, axum::body::Body>,
H: axum::handler::Handler<T, S>,
T: 'static;
}
@ -1803,7 +1764,7 @@ where
handler: H,
) -> Self
where
H: axum::handler::Handler<T, S, axum::body::Body>,
H: axum::handler::Handler<T, S>,
T: 'static,
{
let mut router = self;