How to Set Up a HTML App with FastAPI, Jinja, Forms & Templates

[ engineering python til 🔥 ] · 3 min read

I usually use Flask to build and deploy REST/web apps. Flask is simple to use and apps are easy to spin up with minimal code. Today, I decided to try FastAPI for my new web app, inspired by @tiangolo’s recent talk.

The switch was easier than expected. FastAPI has great documentation and this article by @amitness was useful. Nonetheless, I couldn’t find any guides on how to serve HTML with FastAPI. Thus, I wrote this simple article to plug the hole on the internet.

Try it out with the GitHub repo here: fastapi-html

First, We Build a REST API

Installing FastAPI is as easy as (more about poetry):

poetry add fastapi uvicorn

Then, we build a simple REST API.

from fastapi import FastAPI

from src.model import spell_number  # Spell a number: 1 -> 'one', 2 -> 'two'

app = FastAPI()


@app.get('/')
def read_root():
    return 'hello world'


@app.get("/rest")
def read_item(num: int):
    result = spell_number(num)
    return {"number_spelled": result}

Let’s start it up…

poetry run uvicorn src.rest:app --reload

And call the REST API. The API takes in a number, and spells it out.

curl -X GET "http://127.0.0.1:8000/rest?num=1234" -H  "accept: application/json"
{"number_spelled":"one thousand, two hundred and thirty-four"}

Now, Let’s Make it Serve HTML

First, we’ll need to install some additional dependencies, specifically python-multipart for HTML forms and jinja for templating.

poetry add jinja2 python-multipart

Then, we’ll create a simple HTML template:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sample Form</title>
</head>
<body>
<form method="post">
    <input type="number" name="num" value="1234"/>
    <input type="submit">
</form>

<p>Result: {{ result }}</p>

</body>
</html>

Next, we write a simple web app that:

  • Mounts the templates directory
  • Receives requests, and…
  • Returns results via our HTML template
from fastapi import FastAPI, Request, Form
from fastapi.templating import Jinja2Templates
from src.model import spell_number

app = FastAPI()
templates = Jinja2Templates(directory="templates/")


@app.get('/')
def read_form():
    return 'hello world'


@app.get("/form")
def form_post(request: Request):
    result = "Type a number"
    return templates.TemplateResponse('form.html', context={'request': request, 'result': result})


@app.post("/form")
def form_post(request: Request, num: int = Form(...)):
    result = spell_number(num)
    return templates.TemplateResponse('form.html', context={'request': request, 'result': result})

Let’s start it up…

poetry run uvicorn src.html:app --reload

And give it a spin. Viola, simple as that.

Web app with fastapi, jinja, forms, templates, and html

Our simple web app with FastAPI, Forms, and Jinja templates

Update: This article trended recently on Made With ML!

References


If you found this useful, please cite this write-up as:

Yan, Ziyou. (Jul 2020). How to Set Up a HTML App with FastAPI, Jinja, Forms & Templates. eugeneyan.com. https://eugeneyan.com/writing/how-to-set-up-html-app-with-fastapi-jinja-forms-templates/.

or

@article{yan2020fastapi,
  title   = {How to Set Up a HTML App with FastAPI, Jinja, Forms & Templates},
  author  = {Yan, Ziyou},
  journal = {eugeneyan.com},
  year    = {2020},
  month   = {Jul},
  url     = {https://eugeneyan.com/writing/how-to-set-up-html-app-with-fastapi-jinja-forms-templates/}
}

Share on:

Browse related tags: [ engineering python til 🔥 ]

Join 9,300+ readers getting updates on machine learning, RecSys, LLMs, and engineering.