FastAPI — Render Template & Redirection

Sarumathy P
featurepreneur
Published in
5 min readMar 4, 2023

FastAPI is a modern, fast, web framework for building APIs with Python 3.7+. With its intuitive design and easy-to-use interface, FastAPI is quickly becoming a popular choice for developers looking to build scalable and high-performance APIs.

In this article, we will cover the basics of FastAPI and show you how to get started building your own APIs.

AGENDA:

  1. Rendering HTML templates.
  2. Redirection.

Rendering HTML templates:

FastAPI does not include built-in support for rendering HTML templates, but it can be achieved by using a template engine like Jinja2 or by using a web framework like Starlette.

pip install starlette==0.10.5
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from starlette.templating import Jinja2Templates
import uvicorn

app = FastAPI()

templates = Jinja2Templates(directory="templates")


@app.get("/",response_class=HTMLResponse)
async def signin(request:Request):
return templates.TemplateResponse("signin.html",context={"request":request})


if(__name__) == '__main__':
uvicorn.run(
"app:app",
host = "0.0.0.0",
port = 8036,
reload = True
)
directory structure

Example code for Signin.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign In</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">Sign In</h4>
</div>
<div class="card-body">
<form action="" method="POST">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Sign In</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

This is just a simple bootstrap page with 2 fields, email, and password.

Run this code using the following command. Before this make sure you have the correct directory structure and you include content in signin.html:

python app.py 

If it is working fine, Go to the link specified in the terminal. http://0.0.0.0:8036/

The Jinja2Templates class is imported from the starlette.templating module and is used to create a template renderer. The directory parameter specifies the directory where the templates are stored. In this case, the templates directory is specified.

The @app.get decorator is used to associate the signin function with the root URL path ("/") of the application. When a client accesses the root URL path, the signin function is called.

The response_class parameter is used to specify the type of response that the function returns. In this case, it is set to HTMLResponse, which is a subclass of Response that is used to return an HTML response.

Inside the signin function, the templates.TemplateResponse class is used to render the signin.html template. The context parameter is used to pass variables to the template. It is mandatory to specify request parameter.

Redirection in FastAPI:

In FastAPI, redirection can be achieved using the RedirectResponse class provided by the fastapi.responses module.

Here’s an example of how you can use RedirectResponse to redirect a user to an URL:

Now the directory structure:

For simplicity, I am going with only one record. If the entered email and password match the user dictionary, then the user is considered valid.

user = {"email": "test4@admin.com", "password": "test123"}

@app.post("/", response_class=RedirectResponse)
async def Validate(request: Request, email: str = Form(...), password: str = Form(...)):
valid_credentials = email == user["email"] and password == user["password"]
if valid_credentials:
return templates.TemplateResponse("success.html", context={"request": request})
else:
redirect_url = request.url_for('signin')+ '?x-error=Invalid+credentials'
return RedirectResponse(redirect_url, status_code=status.HTTP_302_FOUND, headers={"x-error": "Invalid credentials"})

This code is a FastAPI view function that handles the POST request to the root path ("/") of the application.

The function is decorated with @app.post to specify that it should be called when a POST request is sent to the root path. The response_class parameter is set to RedirectResponse indicate that the function returns a redirect response.

To Retrieve the user input, you have to specify them as parameters to the function.

name: datatype = Form(...)

The Form function is used to define the input parameters for a POST request that expects form-encoded data.

Here, name is the value you have given in the name attribute of the html element. Example:

<input type="email" class="form-control" id="email" name="email" required>

Consider email: str = Form(...) In this case, “email” is the name of the input parameter and “str” is the data type for that parameter, indicating that the value of the “email” parameter should be a string.

The function takes two parameters: request, which is the request object containing information about the request, and email and password, which are obtained from the submitted form data using the Form class.

The function checks whether the submitted email and password match the values stored in the user dictionary. If the credentials are valid, the function returns a TemplateResponse the object that renders the success.html template.

If the credentials are invalid, the function constructs a redirect URL that includes a query parameter x-error with the value "Invalid credentials". The url_for() method generates the URL for the signin endpoint, which is the view function for the sign-in page. The RedirectResponse function is called with the redirect_url and the status_code parameter is set to HTTP_302_FOUND, indicating that the response should be a 302 (Found) redirect. Additionally, a custom header named x-error is added to the response with the value "Invalid credentials". This header can provide additional information to the client about the error.

Make sure to include success.html file with desired content.

Now, The entire code is

from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse, RedirectResponse
import starlette.status as status
from starlette.templating import Jinja2Templates
import uvicorn

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

user = {"email": "test4@admin.com", "password": "test123"}


@app.get("/", response_class=HTMLResponse)
async def signin(request: Request):
return templates.TemplateResponse("signin.html", context={"request": request})


@app.post("/", response_class=RedirectResponse)
async def Validate(request: Request, email: str = Form(...), password: str = Form(...)):
if(email==user["email"] and password==user["password"]):
return templates.TemplateResponse("success.html",context={"request":request})
else:
redirect_url = request.url_for('signin')+ '?x-error=Invalid+credentials'
return RedirectResponse(redirect_url, status_code=status.HTTP_302_FOUND, headers={"x-error": "Invalid credentials"})


if __name__ == '__main__':
uvicorn.run("app:app", host="0.0.0.0", port=8036, reload=True)

Javascript code to show a pop-up if the credentials are invalid before redirecting to Sign in page.

    <script>
console.log('Script loaded!');
const urlParams = new URLSearchParams(window.location.search);
const error = urlParams.get('x-error');
if (error === 'Invalid credentials') {
console.log('Invalid credentials!');
alert('Invalid credentials! Redirecting to signin page');
}
</script>

This should be included at the end of your signin.html page.

Overall, this code handles form submission, checks if the credentials are valid, and redirects the user to the success page or the login page with an error message in the query parameter and a custom header.

In case you want the entire code along with HTML pages:

https://github.com/SarumathyPrabakaran/Fastapi-signin-example

Thank you. I hope it helps.

--

--