AnswerDotAI / fasthtml

The fastest way to create an HTML app
https://fastht.ml/
Apache License 2.0
5.46k stars 232 forks source link

Support Reverse URL lookups by exposing `url_for` #189

Closed chrisjsimpson closed 2 months ago

chrisjsimpson commented 3 months ago

Small description

Starlette supports reverse url lookups via url_for, to use it requires endpoints must provide a name.

By default, fasthtml.core.RouteX routes are called _endp

app.routes[2]          
RouteX(path='/', name='_endp', methods=['GET', 'HEAD'])

FastHTML routes can be named, and the request context passed in e.g.

@rt("/toggle/{tid}", name="toggle")
def get(tid: int, req):  # noqa: F811
    todo = todos[tid]
    todo.done = not todo.done
    return todos.update(todo)

Results in:

app.routes[3]
RouteX(path='/toggle/{tid}', name='toggle', methods=['GET', 'HEAD'])

However url_for can't be called on them in the same way

(Pdb) req                  
<starlette.requests.Request object at 0x71ccc57c6090>
(Pdb) req.url_for
<bound method HTTPConnection.url_for of <starlette.requests.Request object at 0x71ccc57c6090>>
(Pdb) req.url_for('toggle')
*** starlette.routing.NoMatchFound: No route exists for name "toggle" and params "".

Proposed solution

Consider exposing the url_for api so that named route may easily be back referenced (useful for things like redirecting, DRY)

jph00 commented 3 months ago

Yes good point -- if you (or anyone else!) have time to create a PR for this, that would be appreciated!

rajbhoyar729 commented 3 months ago

can you assign it to me I want to work on this

rajbhoyar729 commented 3 months ago

Thank you

jph00 commented 3 months ago

How you getting along @rajbhoyar729? Lemme know if you need any help.

rajbhoyar729 commented 3 months ago

@jph00 thank if I need any help i will ask for sure

rajbhoyar729 commented 3 months ago

@jph00 I think i will need a till explanation on the task can you please help me a little bro

jph00 commented 3 months ago

@jph00 I think i will need a till explanation on the task can you please help me a little bro

I'll take a look at it, no worries.

rajbhoyar729 commented 3 months ago

I want to work on it can you please guide me a little as its my first time so please give me the opportunity to learn and solve the issue i was just asking for a little guidence

jph00 commented 3 months ago

Understood -- keep an eye out for "Google first issue" labels for stuff that's good for a first time. You picked an extremely technical and complex issue in this case unfortuately! :D

pydanny commented 3 months ago

Hey @chrisjsimpson, the url_for functionality is built into the request object that FastHTML inherits from Starlette. Here's a simple application that serves as proof:

from fasthtml.common import *
from random import randint

app, rt = fast_app()

@rt('/', name='index')
def get(req):
    url = req.url_for('toggle', tid=randint(1,100))
    return Titled("Index",       
        P(A(href=req.url_for('Thing'))(req.url_for('Thing'))),
        P(A(href=url)(url))        
    )

@rt('/thing1', name='Thing')
def get(req):
    return Titled("Thing", P(A(href=req.url_for('index'))(req.url_for('index'))))

@rt("/toggle/{tid}", name="toggle")
def get(tid: int, req):
    return Titled("Toggle",
        P(f"Toggle ID {tid}"),
        P(A(href=req.url_for('index'))(req.url_for('index')))              
    )

serve()

We'll document it shortly and share in this ticket. Then close it. However, if it turns out that your request isn't accounted for, let me know and I'll reopen the ticket and discuss it together. 😄

Pjt727 commented 2 months ago

You can also do app.url_path_for(...) with the app object I find this useful if I am making a component which needs to reverse a URL and I don't want to pass the request into the function which makes the component