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()

def read_root():
    return 'hello world'

def read_item(num: int):
    result = spell_number(num)
    return {"number_spelled": result}

Let’s start it up…

poetry run uvicorn --reload

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

curl -X GET "" -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">
    <meta charset="UTF-8">
    <title>Sample Form</title>
<form method="post">
    <input type="number" name="num" value="1234"/>
    <input type="submit">

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


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/")

def read_form():
    return 'hello world'

def form_post(request: Request):
    result = "Type a number"
    return templates.TemplateResponse('form.html', context={'request': request, 'result': result})"/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!


Share on:

Browse related tags: [ engineering python til ]

Want weekly updates?

I write about effective data science, ML in production, & career growth.

    Welcome gift: A 5-day email course on How to be an Effective Data Scientist 🚀