Understanding FastHTML Routes, Requests, and Redirects
In this tutorial we'll look at the simplest routes and route handlers you can create with FastHTML. We'll define the handlers as little functions, and then call them as we would any other Python function. After that, we'll make simple GET requests to a simple index route/handler, a parameterized one, and a parameterized one with a redirect.
## Setup
```python
from fasthtml.common import *
```
```python
app,rt = fast_app(pico=False)
```
We start with a FastHTML app as usual. `fast_app` is a convenience wrapper for `FastHTML` with some nice defaults.
```python
cli = Client(app)
cli
```
We set up an HTTP client to make requests with. `Client` is defined in `fasthtml.core` and wraps httpx's `AsyncClient`.
Here's a really simple index route handler, to give us something to request. `@rt` is my favorite way to define routes. It makes the index route in particular quick to type out fast because you don't even need a route string.
```python
r = cli.get('/')
r
```
We requested that page and got a successful 200 response with our client!
```python
r.text
```
The response contains this text. If you look closely, you'll see it's a full HTML page containing `<h1>My Homepage</h1>` toward the end.
Here you see a route defined with `@rt` plus a parameterized route string.
The string value of `pagename` from the route turns into the `pagename` argument to the `page` function.
Then it's used in the function definition any way we want. For simple examples like this, I use `Titled` to create quick web pages with the string used twice: as a `<title>` and `<h1>` element.
You can call a route handler function like `page("HEYHEYHEYHEY")` manually, like you would any other Python function. This can be good when you want to make sure your function behaves correctly.
```python
to_xml(heypage)
```
When you pass the returned value into `to_xml`, you can see that you only have a subset of an HTML page. When you call a route handler function manually, you're not making a full HTTP request.
## Making a Full HTTP Request
```python
rp = cli.get('/pages/HEYHEYHEYHEY')
rp
```
This is much more like typing `example.com/pages/HEYHEYHEYHEY` in your browser. You get not just what the function returns, but a whole HTTP request-response round trip.
```python
rp.text
```
You can inspect the response text like you would the HTTP response of any site. Now you see why I capitalized `pagename` and made it so long and obvious. That makes it easy to spot in the 2 places it shows up in the response string: in the title and in the h1 within the main element.
```python
rp.headers
```
The response has HTTP response headers.
## Implementing a Redirect
Now imagine the above route had an old location that we needed to redirect from.
Here we define a second route with the old URL path string. It returns a redirect pointing to the new location. The redirect uses the `Redirect` class from fasthtml.core.
## Making a Request and Inspecting the Redirect's Response
Now we see a 200 response, content, and no location!
```python
rop2.text
```
This looks like the HTTP response for the new route, which is what we want to see.
## Wrapping Up
We've seen how FastHTML makes it easy to create routes and handle HTTP requests. We covered:
- Creating a simple homepage with `@rt`
- Adding a parameterized route with `@rt('/pages/{pagename}')`
- Testing route handlers by calling them directly as Python functions
- Making HTTP requests with FastHTML's `Client`
- Setting up redirects and seeing how they work both with and without following them
What I love here is how much FastHTML development feels so much like regular Python development. You can call handlers like normal functions to make sure they work as expected, and they still work great as full web endpoints.