From b921512b19850fd16e8ae3499d6c4f1c6537854d Mon Sep 17 00:00:00 2001 From: ohmeow Date: Wed, 4 Dec 2024 13:46:21 -0800 Subject: [PATCH] added explantion and short demo of APIRouter in action --- nbs/ref/handlers.ipynb | 162 +++++++++++++++++++++++++++++++++-------- 1 file changed, 133 insertions(+), 29 deletions(-) diff --git a/nbs/ref/handlers.ipynb b/nbs/ref/handlers.ipynb index 07b89d17..eca9d5f9 100644 --- a/nbs/ref/handlers.ipynb +++ b/nbs/ref/handlers.ipynb @@ -358,12 +358,12 @@ " \n", " \n", " \n", "

bar

\n", @@ -678,7 +678,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/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", + "/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", " if arg!='resp': warn(f\"`{arg} has no type annotation and is not a recognised special name, so is ignored.\")\n" ] }, @@ -1252,12 +1252,12 @@ " \n", " \n", " \n", "

hi

\n", @@ -1288,6 +1288,113 @@ "- `(Meta(property='image'), Meta(property='site_name'))` defines two meta tags, which are both placed in the head." ] }, + { + "cell_type": "markdown", + "id": "403fcae3", + "metadata": {}, + "source": [ + "## APIRouter" + ] + }, + { + "cell_type": "markdown", + "id": "f8138c07", + "metadata": {}, + "source": [ + "`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", + "\n", + "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." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5988523d", + "metadata": {}, + "outputs": [], + "source": [ + "# products.py\n", + "ar = APIRouter(prefix=\"/products\")\n", + "\n", + "@ar(\"/all\")\n", + "def all_products(req):\n", + " return Div(\n", + " \"Welcome to the Products Page! Click the button below to look at the details for product 42\",\n", + " Div(\n", + " Button(\n", + " \"Details\",\n", + " hx_get=req.url_for(\"details\", pid=42),\n", + " hx_target=\"#products_list\",\n", + " hx_swap=\"outerHTML\",\n", + " ),\n", + " ),\n", + " id=\"products_list\",\n", + " )\n", + "\n", + "\n", + "@ar.get(\"/{pid}\", name=\"details\")\n", + "def details(pid: int):\n", + " return f\"Here are the product details for ID: {pid}\"" + ] + }, + { + "cell_type": "markdown", + "id": "c7b2325a", + "metadata": {}, + "source": [ + "Since we specified the `prefix=/products` in our hypothetical `products.py` file, all routes defined in that file will be found under `/products`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "001ff0b8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/products/all\n", + "/products/{pid}\n" + ] + } + ], + "source": [ + "print(str(ar.rt_funcs.all_products))\n", + "print(str(ar.rt_funcs.details))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49795185", + "metadata": {}, + "outputs": [], + "source": [ + "# main.py\n", + "# from products import ar\n", + "\n", + "app, rt = fast_app()\n", + "ar.to_app(app)\n", + "\n", + "@rt\n", + "def index():\n", + " return Div(\n", + " \"Click me for a look at our products\",\n", + " hx_get=ar.rt_funcs.all_products,\n", + " hx_swap=\"outerHTML\",\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "7eb1a33f", + "metadata": {}, + "source": [ + "Note how you can reference our python route functions via `APIRouter.rt_funcs` in your `hx_{http_method}` calls like normal." + ] + }, { "cell_type": "markdown", "id": "311ca66a", @@ -1306,14 +1413,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Alexis\n", - "Missing required field: username\n" + "404 Not Found\n", + "404 Not Found\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": null, @@ -1353,7 +1460,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "unknown name\n" + "404 Not Found\n" ] } ], @@ -1383,7 +1490,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{\"a\":1,\"b\":\"foo\",\"nm\":\"me\"}\n" + "404 Not Found\n" ] } ], @@ -1422,7 +1529,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{\"a\":\"1\",\"b\":\"foo\"}\n" + "404 Not Found\n" ] } ], @@ -1454,7 +1561,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{\"a\":\"1\",\"b\":\"foo\"}\n" + "404 Not Found\n" ] } ], @@ -1486,7 +1593,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{\"a\":1,\"b\":\"foo\"}\n" + "404 Not Found\n" ] } ], @@ -1518,7 +1625,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "a: 1; b: foo\n" + "404 Not Found\n" ] } ], @@ -1552,10 +1659,7 @@ "name": "stdout", "output_type": "stream", "text": [ - " It worked!\n", - "

It worked!

\n", - "

15, Lorem

\n", - "
\n" + "404 Not Found\n" ] } ], @@ -1599,13 +1703,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n" + "404 Not Found\n" ] }, { "data": { "text/plain": [ - "'Cookie was set at time 14:16:57.084240'" + "'404 Not Found'" ] }, "execution_count": null, @@ -1647,7 +1751,7 @@ { "data": { "text/plain": [ - "HttpHeader(k='set-cookie', v='now=\"2024-10-24 14:16:57.121212\"; Path=/; SameSite=lax')" + "HttpHeader(k='set-cookie', v='now=\"2024-12-04 13:45:24.154187\"; Path=/; SameSite=lax')" ] }, "execution_count": null, @@ -1689,13 +1793,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "Set to 2024-10-24 14:16:57.168313\n" + "Set to 2024-12-04 13:45:24.159764\n" ] }, { "data": { "text/plain": [ - "'Session time: 2024-10-24 14:16:57.168313'" + "'Session time: 2024-12-04 13:45:24.159764'" ] }, "execution_count": null, @@ -1864,7 +1968,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "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" + "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" ] } ], @@ -1913,12 +2017,12 @@ " \n", " \n", " \n", "
nope
\n",