Skip to content

Commit b921512

Browse files
committed
added explantion and short demo of APIRouter in action
1 parent 7d1434f commit b921512

File tree

1 file changed

+133
-29
lines changed

1 file changed

+133
-29
lines changed

nbs/ref/handlers.ipynb

Lines changed: 133 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,12 @@
358358
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\">\n",
359359
"<script src=\"https://unpkg.com/htmx.org@next/dist/htmx.min.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/answerdotai/[email protected]/fasthtml.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/answerdotai/surreal@main/surreal.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js\"></script><script>\n",
360360
" function sendmsg() {\n",
361-
" window.parent.postMessage({height: document.documentElement.offsetHeight}, &#x27;*&#x27;);\n",
361+
" window.parent.postMessage({height: document.documentElement.offsetHeight}, '*');\n",
362362
" }\n",
363363
" window.onload = function() {\n",
364364
" sendmsg();\n",
365-
" document.body.addEventListener(&#x27;htmx:afterSettle&#x27;, sendmsg);\n",
366-
" document.body.addEventListener(&#x27;htmx:wsAfterMessage&#x27;, sendmsg);\n",
365+
" document.body.addEventListener('htmx:afterSettle', sendmsg);\n",
366+
" document.body.addEventListener('htmx:wsAfterMessage', sendmsg);\n",
367367
" };</script> </head>\n",
368368
" <body>\n",
369369
" <h1>bar</h1>\n",
@@ -678,7 +678,7 @@
678678
"name": "stderr",
679679
"output_type": "stream",
680680
"text": [
681-
"/Users/jhoward/Documents/GitHub/fasthtml/fasthtml/core.py:185: UserWarning: `nope has no type annotation and is not a recognised special name, so is ignored.\n",
681+
"/Users/wgilliam/development/projects/aai/fasthtml/fasthtml/core.py:188: UserWarning: `nope has no type annotation and is not a recognised special name, so is ignored.\n",
682682
" if arg!='resp': warn(f\"`{arg} has no type annotation and is not a recognised special name, so is ignored.\")\n"
683683
]
684684
},
@@ -1252,12 +1252,12 @@
12521252
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\">\n",
12531253
"<script src=\"https://unpkg.com/htmx.org@next/dist/htmx.min.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/answerdotai/[email protected]/fasthtml.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/answerdotai/surreal@main/surreal.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js\"></script><script>\n",
12541254
" function sendmsg() {\n",
1255-
" window.parent.postMessage({height: document.documentElement.offsetHeight}, &#x27;*&#x27;);\n",
1255+
" window.parent.postMessage({height: document.documentElement.offsetHeight}, '*');\n",
12561256
" }\n",
12571257
" window.onload = function() {\n",
12581258
" sendmsg();\n",
1259-
" document.body.addEventListener(&#x27;htmx:afterSettle&#x27;, sendmsg);\n",
1260-
" document.body.addEventListener(&#x27;htmx:wsAfterMessage&#x27;, sendmsg);\n",
1259+
" document.body.addEventListener('htmx:afterSettle', sendmsg);\n",
1260+
" document.body.addEventListener('htmx:wsAfterMessage', sendmsg);\n",
12611261
" };</script> </head>\n",
12621262
" <body>\n",
12631263
" <h1>hi</h1>\n",
@@ -1288,6 +1288,113 @@
12881288
"- `(Meta(property='image'), Meta(property='site_name'))` defines two meta tags, which are both placed in the head."
12891289
]
12901290
},
1291+
{
1292+
"cell_type": "markdown",
1293+
"id": "403fcae3",
1294+
"metadata": {},
1295+
"source": [
1296+
"## APIRouter"
1297+
]
1298+
},
1299+
{
1300+
"cell_type": "markdown",
1301+
"id": "f8138c07",
1302+
"metadata": {},
1303+
"source": [
1304+
"`APIRouter` is useful when you want to split your application routes across multiple `.py` files that are part of a single FastHTMl application. It accepts an optional `prefix` argument that will be applied to all routes within that instance of `APIRouter`.\n",
1305+
"\n",
1306+
"Below we define several hypothetical product related routes in a `products.py` and then demonstrate how they can seamlessly be incorporated into a FastHTML app instance."
1307+
]
1308+
},
1309+
{
1310+
"cell_type": "code",
1311+
"execution_count": null,
1312+
"id": "5988523d",
1313+
"metadata": {},
1314+
"outputs": [],
1315+
"source": [
1316+
"# products.py\n",
1317+
"ar = APIRouter(prefix=\"/products\")\n",
1318+
"\n",
1319+
"@ar(\"/all\")\n",
1320+
"def all_products(req):\n",
1321+
" return Div(\n",
1322+
" \"Welcome to the Products Page! Click the button below to look at the details for product 42\",\n",
1323+
" Div(\n",
1324+
" Button(\n",
1325+
" \"Details\",\n",
1326+
" hx_get=req.url_for(\"details\", pid=42),\n",
1327+
" hx_target=\"#products_list\",\n",
1328+
" hx_swap=\"outerHTML\",\n",
1329+
" ),\n",
1330+
" ),\n",
1331+
" id=\"products_list\",\n",
1332+
" )\n",
1333+
"\n",
1334+
"\n",
1335+
"@ar.get(\"/{pid}\", name=\"details\")\n",
1336+
"def details(pid: int):\n",
1337+
" return f\"Here are the product details for ID: {pid}\""
1338+
]
1339+
},
1340+
{
1341+
"cell_type": "markdown",
1342+
"id": "c7b2325a",
1343+
"metadata": {},
1344+
"source": [
1345+
"Since we specified the `prefix=/products` in our hypothetical `products.py` file, all routes defined in that file will be found under `/products`."
1346+
]
1347+
},
1348+
{
1349+
"cell_type": "code",
1350+
"execution_count": null,
1351+
"id": "001ff0b8",
1352+
"metadata": {},
1353+
"outputs": [
1354+
{
1355+
"name": "stdout",
1356+
"output_type": "stream",
1357+
"text": [
1358+
"/products/all\n",
1359+
"/products/{pid}\n"
1360+
]
1361+
}
1362+
],
1363+
"source": [
1364+
"print(str(ar.rt_funcs.all_products))\n",
1365+
"print(str(ar.rt_funcs.details))"
1366+
]
1367+
},
1368+
{
1369+
"cell_type": "code",
1370+
"execution_count": null,
1371+
"id": "49795185",
1372+
"metadata": {},
1373+
"outputs": [],
1374+
"source": [
1375+
"# main.py\n",
1376+
"# from products import ar\n",
1377+
"\n",
1378+
"app, rt = fast_app()\n",
1379+
"ar.to_app(app)\n",
1380+
"\n",
1381+
"@rt\n",
1382+
"def index():\n",
1383+
" return Div(\n",
1384+
" \"Click me for a look at our products\",\n",
1385+
" hx_get=ar.rt_funcs.all_products,\n",
1386+
" hx_swap=\"outerHTML\",\n",
1387+
" )"
1388+
]
1389+
},
1390+
{
1391+
"cell_type": "markdown",
1392+
"id": "7eb1a33f",
1393+
"metadata": {},
1394+
"source": [
1395+
"Note how you can reference our python route functions via `APIRouter.rt_funcs` in your `hx_{http_method}` calls like normal."
1396+
]
1397+
},
12911398
{
12921399
"cell_type": "markdown",
12931400
"id": "311ca66a",
@@ -1306,14 +1413,14 @@
13061413
"name": "stdout",
13071414
"output_type": "stream",
13081415
"text": [
1309-
"Alexis\n",
1310-
"Missing required field: username\n"
1416+
"404 Not Found\n",
1417+
"404 Not Found\n"
13111418
]
13121419
},
13131420
{
13141421
"data": {
13151422
"text/plain": [
1316-
"<Response [400 Bad Request]>"
1423+
"<Response [404 Not Found]>"
13171424
]
13181425
},
13191426
"execution_count": null,
@@ -1353,7 +1460,7 @@
13531460
"name": "stdout",
13541461
"output_type": "stream",
13551462
"text": [
1356-
"unknown name\n"
1463+
"404 Not Found\n"
13571464
]
13581465
}
13591466
],
@@ -1383,7 +1490,7 @@
13831490
"name": "stdout",
13841491
"output_type": "stream",
13851492
"text": [
1386-
"{\"a\":1,\"b\":\"foo\",\"nm\":\"me\"}\n"
1493+
"404 Not Found\n"
13871494
]
13881495
}
13891496
],
@@ -1422,7 +1529,7 @@
14221529
"name": "stdout",
14231530
"output_type": "stream",
14241531
"text": [
1425-
"{\"a\":\"1\",\"b\":\"foo\"}\n"
1532+
"404 Not Found\n"
14261533
]
14271534
}
14281535
],
@@ -1454,7 +1561,7 @@
14541561
"name": "stdout",
14551562
"output_type": "stream",
14561563
"text": [
1457-
"{\"a\":\"1\",\"b\":\"foo\"}\n"
1564+
"404 Not Found\n"
14581565
]
14591566
}
14601567
],
@@ -1486,7 +1593,7 @@
14861593
"name": "stdout",
14871594
"output_type": "stream",
14881595
"text": [
1489-
"{\"a\":1,\"b\":\"foo\"}\n"
1596+
"404 Not Found\n"
14901597
]
14911598
}
14921599
],
@@ -1518,7 +1625,7 @@
15181625
"name": "stdout",
15191626
"output_type": "stream",
15201627
"text": [
1521-
"a: 1; b: foo\n"
1628+
"404 Not Found\n"
15221629
]
15231630
}
15241631
],
@@ -1552,10 +1659,7 @@
15521659
"name": "stdout",
15531660
"output_type": "stream",
15541661
"text": [
1555-
" <title>It worked!</title>\n",
1556-
"<main class=\"container\"> <h1>It worked!</h1>\n",
1557-
" <p>15, Lorem</p>\n",
1558-
"</main>\n"
1662+
"404 Not Found\n"
15591663
]
15601664
}
15611665
],
@@ -1599,13 +1703,13 @@
15991703
"name": "stdout",
16001704
"output_type": "stream",
16011705
"text": [
1602-
"\n"
1706+
"404 Not Found\n"
16031707
]
16041708
},
16051709
{
16061710
"data": {
16071711
"text/plain": [
1608-
"'Cookie was set at time 14:16:57.084240'"
1712+
"'404 Not Found'"
16091713
]
16101714
},
16111715
"execution_count": null,
@@ -1647,7 +1751,7 @@
16471751
{
16481752
"data": {
16491753
"text/plain": [
1650-
"HttpHeader(k='set-cookie', v='now=\"2024-10-24 14:16:57.121212\"; Path=/; SameSite=lax')"
1754+
"HttpHeader(k='set-cookie', v='now=\"2024-12-04 13:45:24.154187\"; Path=/; SameSite=lax')"
16511755
]
16521756
},
16531757
"execution_count": null,
@@ -1689,13 +1793,13 @@
16891793
"name": "stdout",
16901794
"output_type": "stream",
16911795
"text": [
1692-
"Set to 2024-10-24 14:16:57.168313\n"
1796+
"Set to 2024-12-04 13:45:24.159764\n"
16931797
]
16941798
},
16951799
{
16961800
"data": {
16971801
"text/plain": [
1698-
"'Session time: 2024-10-24 14:16:57.168313'"
1802+
"'Session time: 2024-12-04 13:45:24.159764'"
16991803
]
17001804
},
17011805
"execution_count": null,
@@ -1864,7 +1968,7 @@
18641968
"name": "stdout",
18651969
"output_type": "stream",
18661970
"text": [
1867-
"Headers({'access-control-allow-origin': '*', 'access-control-allow-methods': 'POST', 'access-control-allow-headers': '*', 'content-length': '0', 'set-cookie': 'session_=eyJhdXRoIjogIjIwMjQtMTAtMjQgMTQ6MTY6NTcuMTY4MzEzIn0=.ZxnKOQ.8x-zyM5rd59ix3PtADan0qfL-bk; path=/; Max-Age=31536000; httponly; samesite=lax'})\n"
1971+
"Headers({'access-control-allow-origin': '*', 'access-control-allow-methods': 'POST', 'access-control-allow-headers': '*', 'content-length': '0', 'set-cookie': 'session_=eyJhdXRoIjogIjIwMjQtMTItMDQgMTM6NDU6MjQuMTU5NzY0In0=.Z1DNdA.GV-NVoOnJeambm9_uE3crhoGH34; path=/; Max-Age=31536000; httponly; samesite=lax'})\n"
18681972
]
18691973
}
18701974
],
@@ -1913,12 +2017,12 @@
19132017
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\">\n",
19142018
"<script src=\"https://unpkg.com/htmx.org@next/dist/htmx.min.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/answerdotai/[email protected]/fasthtml.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/answerdotai/surreal@main/surreal.js\"></script><script src=\"https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js\"></script><script>\n",
19152019
" function sendmsg() {\n",
1916-
" window.parent.postMessage({height: document.documentElement.offsetHeight}, &#x27;*&#x27;);\n",
2020+
" window.parent.postMessage({height: document.documentElement.offsetHeight}, '*');\n",
19172021
" }\n",
19182022
" window.onload = function() {\n",
19192023
" sendmsg();\n",
1920-
" document.body.addEventListener(&#x27;htmx:afterSettle&#x27;, sendmsg);\n",
1921-
" document.body.addEventListener(&#x27;htmx:wsAfterMessage&#x27;, sendmsg);\n",
2024+
" document.body.addEventListener('htmx:afterSettle', sendmsg);\n",
2025+
" document.body.addEventListener('htmx:wsAfterMessage', sendmsg);\n",
19222026
" };</script> </head>\n",
19232027
" <body>\n",
19242028
" <div>nope</div>\n",

0 commit comments

Comments
 (0)