fasthtml is a library for writing fast and scalable Starlette-powered web applications, without having to learn much (if any!) Starlette. Instead, you just use plain python functions for each page in your app – you don’t even need to learn Javascript. The finished app will be about as fast as a Python web server can be (which is pretty fast – e.g. Instagram runs on Python), and you can create pretty much anything. This isn’t one of those stripped-down dashboard making thingies.
+
This is a way to write real web applications, without the fuss.
+
To learn how to use it, please visit the documentation.
+
+
Install
+
pip install python-fasthtml
+
+
+
How to use
+
Import fasthtml, and you’ll probably want the widgets from fastcore.xml too.
+
+
from fasthtml import*
+from fastcore.xml import*
+
+
Create your app.
+
+
app = FastHTML()
+
+
Create your routes. The syntax is largely the same as the wonderful FastAPI (which is what you should be using instead of this if you’re creating a JSON service. FastHTML is for mainly for making HTML web apps, not APIs).
+
Note that you need to include the types of your parameters, so that FastHTML knows what to pass to your function. Here, we’re just expecting a string:
+
+
@app.get('/user/{nm}')
+def get_nm(nm:str): returnf"Good day to you, {nm}!"
+
+
Normally you’d save this into a file such as main.py, and then run it in uvicorn using:
+
uvicorn main:app
+
However, for testing, we can use Starlette’s TestClient to try it out:
TestClient uses httpx behind the scenes, so it returns a httpx.Response, which has a text attribute with our response body:
+
+
r.text
+
+
'Good day to you, Jeremy!'
+
+
+
FastHTML has special handling of tags created using fastcore.xml, so you can return web pages without worrying about Jinja, templates, or any of that stuff. This also means you can pip install styled rich component libraries, since it’s all just pure python:
+
+
@app.get('/html/{idx}')
+asyncdef get_html(idx:int):
+return Body(
+ H4("Wow look here"),
+ P(f'It looks like you are visitor {idx}! Next is {idx+1}.')
+ )
+
+
+
from IPython import display
+
+
+
display.HTML(client.get('/html/1').text)
+
+
+
+Wow look here
+
+
+It looks like you are visitor 1! Next is 2.
+
+
+
+
+
+
+
Features
+
Here’s a brief demo of all the features of the library:
{"type":"http","http_version":"1.1","method":"GET","path":"/","raw_path":"b'/'","root_path":"","scheme":"http","query_string":"b''","headers":"[(b'host', b'testserver'), (b'accept', b'*/*'), (b'accept-encoding', b'gzip, deflate, br'), (b'connection', b'keep-alive'), (b'user-agent', b'testclient')]","client":"['testclient', 50000]","server":"['testserver', 80]","extensions":"{'http.response.debug': {}}","state":"{}","app":"<starlette.applications.Starlette object at 0x12f39c990>","starlette.exception_handlers":"({<class 'starlette.exceptions.HTTPException'>: <bound method ExceptionMiddleware.http_exception of <starlette.middleware.exceptions.ExceptionMiddleware object at 0x12f39dcd0>>, <class 'starlette.exceptions.WebSocketException'>: <bound method ExceptionMiddleware.websocket_exception of <starlette.middleware.exceptions.ExceptionMiddleware object at 0x12f39dcd0>>}, {})","router":"<starlette.routing.Router object at 0x12f39c510>","endpoint":"<function _wrap_ep.<locals>._f at 0x129bef6a0>","path_params":"{}"}
+
+
+
+
client.get('/user/jph').text
+
+
'Good day to you, jph!'
+
+
+
+
@app.get('/html/{idx}')
+asyncdef get_html(idx:int):
+return Body(
+ H4("Wow look here"),
+ P(f'It looks like you are visitor {idx}! Next is {idx+1}.')
+ )