feat: allow reusing the same endpoint for server functions with different HTTP verbs in their input encodings
This commit is contained in:
parent
24775fb59b
commit
4fa72a94fb
|
@ -302,8 +302,9 @@ pub fn handle_server_fns_with_context(
|
||||||
let additional_context = additional_context.clone();
|
let additional_context = additional_context.clone();
|
||||||
|
|
||||||
let path = req.path();
|
let path = req.path();
|
||||||
|
let method = req.method();
|
||||||
if let Some(mut service) =
|
if let Some(mut service) =
|
||||||
server_fn::actix::get_server_fn_service(path)
|
server_fn::actix::get_server_fn_service(path, method)
|
||||||
{
|
{
|
||||||
let owner = Owner::new();
|
let owner = Owner::new();
|
||||||
owner
|
owner
|
||||||
|
@ -1323,7 +1324,7 @@ impl LeptosRoutes for &mut ServiceConfig {
|
||||||
let mut router = self;
|
let mut router = self;
|
||||||
|
|
||||||
// register server functions first to allow for wildcard route in Leptos's Router
|
// register server functions first to allow for wildcard route in Leptos's Router
|
||||||
for (path, _) in server_fn::actix::server_fn_paths() {
|
for (path, method) in server_fn::actix::server_fn_paths() {
|
||||||
let additional_context = additional_context.clone();
|
let additional_context = additional_context.clone();
|
||||||
let handler = handle_server_fns_with_context(additional_context);
|
let handler = handle_server_fns_with_context(additional_context);
|
||||||
router = router.route(path, handler);
|
router = router.route(path, handler);
|
||||||
|
|
|
@ -313,10 +313,13 @@ async fn handle_server_fns_inner(
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
use server_fn::middleware::Service;
|
use server_fn::middleware::Service;
|
||||||
|
|
||||||
|
let method = req.method().clone();
|
||||||
let path = req.uri().path().to_string();
|
let path = req.uri().path().to_string();
|
||||||
let (req, parts) = generate_request_and_parts(req);
|
let (req, parts) = generate_request_and_parts(req);
|
||||||
|
|
||||||
if let Some(mut service) = server_fn::axum::get_server_fn_service(&path) {
|
if let Some(mut service) =
|
||||||
|
server_fn::axum::get_server_fn_service(&path, method)
|
||||||
|
{
|
||||||
let owner = Owner::new();
|
let owner = Owner::new();
|
||||||
owner
|
owner
|
||||||
.with(|| {
|
.with(|| {
|
||||||
|
|
|
@ -362,7 +362,9 @@ macro_rules! initialize_server_fn_map {
|
||||||
once_cell::sync::Lazy::new(|| {
|
once_cell::sync::Lazy::new(|| {
|
||||||
$crate::inventory::iter::<ServerFnTraitObj<$req, $res>>
|
$crate::inventory::iter::<ServerFnTraitObj<$req, $res>>
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|obj| (obj.path(), obj.clone()))
|
.map(|obj| {
|
||||||
|
((obj.path().to_string(), obj.method()), obj.clone())
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -442,7 +444,7 @@ impl<Req, Res> Clone for ServerFnTraitObj<Req, Res> {
|
||||||
|
|
||||||
#[allow(unused)] // used by server integrations
|
#[allow(unused)] // used by server integrations
|
||||||
type LazyServerFnMap<Req, Res> =
|
type LazyServerFnMap<Req, Res> =
|
||||||
Lazy<DashMap<&'static str, ServerFnTraitObj<Req, Res>>>;
|
Lazy<DashMap<(String, Method), ServerFnTraitObj<Req, Res>>>;
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
impl<Req: 'static, Res: 'static> inventory::Collect
|
impl<Req: 'static, Res: 'static> inventory::Collect
|
||||||
|
@ -481,7 +483,7 @@ pub mod axum {
|
||||||
> + 'static,
|
> + 'static,
|
||||||
{
|
{
|
||||||
REGISTERED_SERVER_FUNCTIONS.insert(
|
REGISTERED_SERVER_FUNCTIONS.insert(
|
||||||
T::PATH,
|
(T::PATH.into(), T::InputEncoding::METHOD),
|
||||||
ServerFnTraitObj::new(
|
ServerFnTraitObj::new(
|
||||||
T::PATH,
|
T::PATH,
|
||||||
T::InputEncoding::METHOD,
|
T::InputEncoding::METHOD,
|
||||||
|
@ -502,7 +504,9 @@ pub mod axum {
|
||||||
pub async fn handle_server_fn(req: Request<Body>) -> Response<Body> {
|
pub async fn handle_server_fn(req: Request<Body>) -> Response<Body> {
|
||||||
let path = req.uri().path();
|
let path = req.uri().path();
|
||||||
|
|
||||||
if let Some(mut service) = get_server_fn_service(path) {
|
if let Some(mut service) =
|
||||||
|
get_server_fn_service(path, req.method().clone())
|
||||||
|
{
|
||||||
service.run(req).await
|
service.run(req).await
|
||||||
} else {
|
} else {
|
||||||
Response::builder()
|
Response::builder()
|
||||||
|
@ -524,8 +528,10 @@ pub mod axum {
|
||||||
/// Returns the server function at the given path as a service that can be modified.
|
/// Returns the server function at the given path as a service that can be modified.
|
||||||
pub fn get_server_fn_service(
|
pub fn get_server_fn_service(
|
||||||
path: &str,
|
path: &str,
|
||||||
|
method: Method,
|
||||||
) -> Option<BoxedService<Request<Body>, Response<Body>>> {
|
) -> Option<BoxedService<Request<Body>, Response<Body>>> {
|
||||||
REGISTERED_SERVER_FUNCTIONS.get(path).map(|server_fn| {
|
let key = (path.into(), method);
|
||||||
|
REGISTERED_SERVER_FUNCTIONS.get(&key).map(|server_fn| {
|
||||||
let middleware = (server_fn.middleware)();
|
let middleware = (server_fn.middleware)();
|
||||||
let mut service = BoxedService::new(server_fn.clone());
|
let mut service = BoxedService::new(server_fn.clone());
|
||||||
for middleware in middleware {
|
for middleware in middleware {
|
||||||
|
@ -565,7 +571,7 @@ pub mod actix {
|
||||||
> + 'static,
|
> + 'static,
|
||||||
{
|
{
|
||||||
REGISTERED_SERVER_FUNCTIONS.insert(
|
REGISTERED_SERVER_FUNCTIONS.insert(
|
||||||
T::PATH,
|
(T::PATH.into(), T::InputEncoding::METHOD),
|
||||||
ServerFnTraitObj::new(
|
ServerFnTraitObj::new(
|
||||||
T::PATH,
|
T::PATH,
|
||||||
T::InputEncoding::METHOD,
|
T::InputEncoding::METHOD,
|
||||||
|
@ -588,13 +594,8 @@ pub mod actix {
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let path = req.uri().path();
|
let path = req.uri().path();
|
||||||
if let Some(server_fn) = REGISTERED_SERVER_FUNCTIONS.get(path) {
|
let method = req.method();
|
||||||
let middleware = (server_fn.middleware)();
|
if let Some(mut service) = get_server_fn_service(path, method) {
|
||||||
// http::Method is the only non-Copy type here
|
|
||||||
let mut service = BoxedService::new(server_fn.clone());
|
|
||||||
for middleware in middleware {
|
|
||||||
service = middleware.layer(service);
|
|
||||||
}
|
|
||||||
service
|
service
|
||||||
.0
|
.0
|
||||||
.run(ActixRequest::from((req, payload)))
|
.run(ActixRequest::from((req, payload)))
|
||||||
|
@ -618,14 +619,31 @@ pub mod actix {
|
||||||
/// Returns the server function at the given path as a service that can be modified.
|
/// Returns the server function at the given path as a service that can be modified.
|
||||||
pub fn get_server_fn_service(
|
pub fn get_server_fn_service(
|
||||||
path: &str,
|
path: &str,
|
||||||
|
method: &actix_web::http::Method,
|
||||||
) -> Option<BoxedService<ActixRequest, ActixResponse>> {
|
) -> Option<BoxedService<ActixRequest, ActixResponse>> {
|
||||||
REGISTERED_SERVER_FUNCTIONS.get(path).map(|server_fn| {
|
use actix_web::http::Method as ActixMethod;
|
||||||
let middleware = (server_fn.middleware)();
|
|
||||||
let mut service = BoxedService::new(server_fn.clone());
|
let method = match *method {
|
||||||
for middleware in middleware {
|
ActixMethod::GET => Method::GET,
|
||||||
service = middleware.layer(service);
|
ActixMethod::POST => Method::POST,
|
||||||
}
|
ActixMethod::PUT => Method::PUT,
|
||||||
service
|
ActixMethod::PATCH => Method::PATCH,
|
||||||
})
|
ActixMethod::DELETE => Method::DELETE,
|
||||||
|
ActixMethod::HEAD => Method::HEAD,
|
||||||
|
ActixMethod::TRACE => Method::TRACE,
|
||||||
|
ActixMethod::OPTIONS => Method::OPTIONS,
|
||||||
|
ActixMethod::CONNECT => Method::CONNECT,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
REGISTERED_SERVER_FUNCTIONS.get(&(path.into(), method)).map(
|
||||||
|
|server_fn| {
|
||||||
|
let middleware = (server_fn.middleware)();
|
||||||
|
let mut service = BoxedService::new(server_fn.clone());
|
||||||
|
for middleware in middleware {
|
||||||
|
service = middleware.layer(service);
|
||||||
|
}
|
||||||
|
service
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue