Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RouteContext::method #1808

Closed
yokomizor opened this issue Sep 29, 2023 · 6 comments · Fixed by #2315
Closed

Add RouteContext::method #1808

yokomizor opened this issue Sep 29, 2023 · 6 comments · Fixed by #2315
Labels
Milestone

Comments

@yokomizor
Copy link

Is your feature request related to a problem? Please describe.
Since Route has a method attribute, it would be nice to have a way to use this value inside components.

Describe the solution you'd like

App.rs

<Route
    path="/path"
    methods=&[Method::Get, Method::Post]
    view=Page />

Page.rs

pub fn Page() -> impl IntoView {
    let route = use_route();

    match route.method() { // <----- This feature request
        Method::Get => todo!(),
        Method::Post => todo!(),
        _ => unreachable!(),
    };

    view! {
        // ...
    }
}
@gbj
Copy link
Collaborator

gbj commented Sep 29, 2023

I'm actually not sure what you're asking for. Are you asking for access to the methods prop (in which case route.method() would return a &[Method], and your match statement doesn't make sense)? Or are you asking for access to the HTTP method in response to which the page is currently being rendered? (in which case it will be Option<Method>, as sometimes your components are being rendered in the browser and there is no HTTP request involved)

@yokomizor
Copy link
Author

Yeah, it was confusing, and I am having a hard time myself trying to put it in words. Let me try again.

Or are you asking for access to the HTTP method in response to which the page is currently being rendered?

Not necessarily the raw HTTP method. It could some sort of "router method" if that makes sense.
If the route was triggered in the browser and no method was defined there, then the default Method::Get could be returned.

I understand that Route path and HTTP path are not the same, but most of the time we map them 1:1 for better graceful degradation.

In other words, most of the time we want to map:

GET /articles/nature

to:

<Route
    path="/articles/:type"
    view=Articles />

Regardless of it being rendered by the browser or by the server, Articles will use the value of :type during render.

Articles has no idea about HTTP, it only knows Route, as it should be. Yet, for graceful degradation purposes, most of the time we will have Route path and HTTP path being a 1:1 map.

Now lets say we have a POST request:

POST /articles/nature

<Route
    path="/articles/:type"
    methods=&[Method::Get, Method::Post]
    view=Articles />

Articles will be rendered as normal, but there is no way to distinguish between a POST and GET from inside the component.

Today it seems that RouteProps::methods are only used to generate integrations with HTTP frameworks, but Leptos has no concept of Method. I think the absence of this concept makes it harder to create these 1:1 mappings for graceful degradation purposes.

A more concrete example can be found here: #1120

This simplistic example is trying to demonstrate how to gracefully degrade when JS is not available, but the implementation is incomplete.

It covers the following cases:

  • JS is not available.
  • JS is available and FavoriteColors was rendered on the server.

These are covered because when FavoriteColors is rendered on the server, favorite_color_form can differ between GET and POST.

But it does not cover the following:

  • JS is available and FavoriteColors was rendered on the browser after some routes navigation.

The case above is not covered because when it is rendered on the browser, it will always send a POST request when calling favorite_color_form.

@gbj
Copy link
Collaborator

gbj commented Sep 29, 2023

As I understand it the answer is that you are looking for the method the current navigation is being rendered in, always interpreting that as GET for a client-side navigation. Which sounds great. And I believe you that it would make that incomplete demo better. It's unlikely I'll have time to work on this any time soon, but if you'd like to make a PR I'd be happy to look at it.

@gbj gbj added the good first issue Good for newcomers label Oct 2, 2023
@gbj gbj added this to the 0.7 milestone Jan 20, 2024
@zoomiti
Copy link
Contributor

zoomiti commented Feb 3, 2024

I'd like to pick this up but I'd like a bit of direction. Would this involve a method on RouteContext that returns the current method? Say a post request on that route should still render that component but the component should be able to query that like in @yokomizor's original comment?

@gbj
Copy link
Collaborator

gbj commented Feb 4, 2024

@zoomiti Yes, that's correct: It is solely a question of adding a method that returns the method by which someone was routed to the current page (using GET if it was a client-side navigation).

In effect, this would mean

  1. adapting the server integrations to not only match on different methods, but provide that information via context to the router
  2. returning that provided method, if it's found, otherwise defaulting to GET

@zoomiti
Copy link
Contributor

zoomiti commented Feb 16, 2024

@gbj So I have a working implementation of this, should I make an accompanying example? For testing purposes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants