FastAPI in Python

Gaurav Kumar
12 min readJan 19, 2024

--

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. It’s built on Starlette for the web parts and Pydantic for the data parts.

Here are some key features of FastAPI:

  1. Fast: It’s one of the fastest Python frameworks available, on par with NodeJS and Go (thanks to Starlette and Pydantic).
  2. Easy: Great editor support. Completion everywhere. Less time debugging.
  3. Fast to code: Increase the speed to develop features by about 200% to 300% with Python type hints.
  4. Less bugs: Reduce about 40% of human (developer) induced errors.
  5. Intuitive: Great editor support. Easy to learn, easy to use, easy to remember.
  6. Short: Minimize code duplication. Multiple features from each parameter declaration.
  7. Robust: Get production-ready code with automatic interactive documentation.
  8. Standards-based: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.
  9. Pythonic: Very pythonic, easy to read and write.

Installation and Setup of FastAPI

To commence your journey with FastAPI, ensure that you have Python installed on your system. If Python3 is not already installed, proceed to install it. Subsequently, install FastAPI by executing the provided command.

pip install fastapi

You also need to install uvicorn

pip install uvicorn

Develop a Basic API

In this context, we are constructing a straightforward web service that greets you with a “Hello” message upon visiting a designated web address. Utilizing FastAPI, achieving this functionality requires only a concise snippet of code. To execute this code, store it in a Python file; in this instance, we are preserving the file under the name main.py.

from fastapi import FastAPI

# Create a FastAPI application
app = FastAPI()

# Define a route at the root web address ("/")
@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}

Now, execute the following command in your terminal:

uvicorn main:app --reload

Once the application is running, open your web browser and navigate to

http://127.0.0.1:8000

Following the execution, you can expect to observe a message presented in your web browser or view the response if you are utilizing an API testing tool such as curl or Postman.

{"message": "Hello, FastAPI!"}

Benefits of FastAPI

FastAPI offers several advantages that contribute to its popularity:

  1. User-Friendly and Accessible
  2. Exceptional Performance
  3. Automated Data Validation
  4. Streamlined Authentication and Authorization
  5. Middleware Integration

Challenges Associated with FastAPI

Exploring FastAPI may present certain challenges, including:

  1. Acquiring Expertise: FastAPI, while crafted for developer ease, might pose a learning curve for individuals unfamiliar with asynchronous programming or web frameworks. Those without prior Python experience may find it beneficial to first acquaint themselves with the language.
  2. Community and Resource Availability: Despite the rapid growth of the FastAPI community, it might not boast the same level of widespread support or comprehensive documentation found in alternative frameworks. Access to tutorials, guides, and community-contributed packages could be more limited in comparison.

Exploring Event Handlers in FastAPI:

Understanding the Mechanism Behind API Events

FastAPI is a Python framework dedicated to API development. In certain scenarios, users may find the need to recognize specific events occurring within the API. FastAPI facilitates this through the utilization of event handlers. This article delves into an examination of the diverse event handlers accessible within the FastAPI framework.

Understanding Event Handlers in FastAPI:
In the realm of FastAPI, an event handler serves as a Python function that is triggered automatically upon the occurrence of predefined events throughout the execution of your application. These handlers empower you to execute custom actions, tailor the behavior of your FastAPI application, and intervene at various stages of its lifecycle. Common applications of event handlers include configuring database connections, executing cleanup tasks, and customizing request and response behaviors.

Categories of FastAPI Event Handlers:
1. Initialization (Startup):
Initialization event handlers are executed when your FastAPI application starts. This phase is ideal for setting up resources or configurations needed for the application’s runtime.

2. Termination (Shutdown):
Termination event handlers are triggered when your FastAPI application is shutting down. This stage is opportune for performing cleanup operations, closing connections, or finalizing any remaining tasks before the application concludes its execution.

FastAPI Startup Event

The Startup Event The Startup event occurs when users initiate the FastAPI application using the command:

uvicorn main:app --reload

In FastAPI, the initialization event is effectively managed to define variables that should be initialized at the commencement of the application. The on_event function provided by FastAPI is employed to determine when this event should be triggered.

Syntax:

@app.on_event("startup")

async def custom_startup_function():

print("Custom Statement during Startup")

Here,

  • function_name: It is the function which you want to call while the startup event is triggered.
  • Statement_startup: It is the statement under the startup function that will be executed.

Example:

Here, we showcase a function, event_startup, designed to execute when the FastAPI app commences, providing a timestamp of the start moment.

from fastapi import FastAPI
import datetime as dt


app = FastAPI()

# Handle the startup event
@app.on_event("startup")
async def event_startup():
print('FastAPI Server started :', dt.datetime.now())

FastAPI Shutdown Event

The Shutdown event in FastAPI is activated when users terminate the application by pressing Ctrl and C simultaneously. This event is crucial for concluding any ongoing indefinite tasks, ensuring a graceful closure of the app. Its handling is facilitated through FastAPI’s on_event function, which identifies the trigger for this event.

@app.on_event("shutdown")

async def custom_startup_function():

print("Custom Statement during Shutdown")

Here,

  • function_name: It is the function which you want to call while the shutdown event is triggered.
  • Statement_shutdown: It is the statement under the shutdown function that will be executed.

Example:

In the given illustration, a function named `event_shutdown` has been crafted to execute upon the closure of the FastAPI app. This function is designed to display the date and time when the application concludes its shutdown process.

from fastapi import FastAPI
import datetime as dt

app = FastAPI()

# Handle the startup event
@app.on_event("shutdown")
async def event_shutdown():
print('FastAPI Server shutdown :', dt.datetime.now())

Output:

Now, press Ctrl+C to see the shutdown event being triggered.

Error Handling in FastAPI

What is Error Handling in FastAPI?

Effective error handling is indispensable in web development to fortify applications for reliability. In FastAPI, a contemporary Python-based web framework for API development, mastery of error handling is imperative to guarantee a seamless response to diverse scenarios, enhancing the robustness of your API.

Ways to Handle Errors in FastAPI

  • Using HTTP status codes
  • Using built-in exception handlers
  • Using custom exception handlers
  • Using middleware
  • Using logging

Error Handling using HTTP Status Codes

FastAPI equips you with HTTP status codes to communicate how the server processed a client request. This approach demonstrates how FastAPI manages errors by leveraging these status codes, which are broadly categorized into five classes:

Syntax:

def function_name() -> Item:
if condition:

raise HTTPException(status_code=HTTP_Code_1, detail=f”error_message_1″)

else:

raise HTTPException(status_code=HTTP_Code_2, detail=f”error_message_2″)

Here,

  • function_name: It is the function which you want to call while testing.
  • condition: It is the check which you want to add to return the error.
  • error_message_1, error_message_2: These are the messages shown to user when there is an error.
  • HTTP_Code_1, HTTP_Code_2: These are the HTTP status codes which we want to display to user along with error message.
# main.py:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class Student(BaseModel):
name: str
roll_number: int

students = {
1: Student(name="GK", roll_number=1),
2: Student(name="AK", roll_number=2),
3: Student(name="SB", roll_number=3),
}

@app.get("/items/{roll_number}")
def query_student_by_roll_number(roll_number: int) -> dict:
if roll_number not in students:
return {"status_code": 404, "message": f"Student with {roll_number=} does not exist."}
else:
return {"status_code": 200, "message": f"Student details are as follows: {students[roll_number]}"}
# test.py:

from fastapi.testclient import TestClient
from main import app

# Create a test client for the FastAPI app
client = TestClient(app)

# Call the function and print the output
response = client.get("/items/1")
print(response.json())

In this instance, error handling is implemented using two status codes — 200 denoting success and 404 indicating an error. A response with code 200 and a message is presented when the roll number exists in the students list, while code 404 with a corresponding message is conveyed if the roll number is absent in the list. The FastAPI framework, along with Pydantic for data validation, is employed for seamless development.

On invoking the function with roll number 1, existing in the student list, it returns a status code of 200 along with a message: “Student details are as follows: {students[roll_number]}”. Conversely, calling the function with roll number 4, which is not present in the student list, results in an error message with a status code of 404, displaying: “Student with {roll_number=} does not exist,” as illustrated in the provided screenshot.

Built-In Exception Handlers in FastAPI

FastAPI utilizes built-in exception handling through HTTP exceptions, which are Python exceptions augmented with additional data. This approach demonstrates how errors can be managed within FastAPI using its inherent exception-handling mechanisms.

Syntax:

def function_name() -> Item:

if condition:

raise HTTPException(status_code=HTTP_Code, detail=f”error_message”)

Here,

  • function_name: It is the function which you want to call while testing.
  • condition: It is the check which you want to add to return the error.
  • error_message: It is the message shown to user when there is an error.
  • HTTP_Code: It is the HTTP status code which we want to display to user along with error message.
# main.py:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class Student(BaseModel):
name: str
roll_number: int
students = {
1: Student(name="GK", roll_number=1),
2: Student(name="AK", roll_number=2),
3: Student(name="SB", roll_number=3),
}
@app.get("/items/{roll_number}")
def query_student_by_roll_number(roll_number: int) -> Student:
if roll_number not in students:
raise HTTPException(status_code=404, detail=f"Student with {roll_number=} does not exist.")
return students[roll_number]
# test.py:

from fastapi.testclient import TestClient
from main import app

# Create a test client for the FastAPI app
client = TestClient(app)

# Call the function and print the output
response = client.get("/items/1")
print(response.json())

In this instance, the code verifies the existence of a student’s roll number in the students list. If the roll number is present, the corresponding student’s details are returned; otherwise, an error message is generated, signaling a non-existent student. Utilizing FastAPI and Pydantic for seamless development, this example demonstrates a robust approach to handling queries.

On calling the function with roll number 1, which corresponds to an existing student in the list, it exhibits the name and roll_number details of the student. Conversely, when invoking roll number 4, which is absent in the student list, it showcases a message stating “{‘detail’: Student with {roll_number=} does not exist.}” as depicted in the provided screenshot.

Custom Exception Handlers in FastAPI

A vital Python library for managing exceptions in Starlette is employed in FastAPI for raising custom exceptions. This approach demonstrates the utilization of custom exception handlers for effective error handling.

Syntax:

class UnicornException(Exception):
def __init__(self, value: str):
self.value = value

# Create a custom exception

@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(status_code=404, content={"message": f"error_message"}, )

async def function_name(roll_number: int):
if condition:
raise UnicornException(value=condition_value)

Here,

  • function_name: It is the function which you want to call while testing.
  • condition: It is the check which you want to add to return the error.
  • error_message: It is the message shown to user when there is an error.
  • condition_value: It is the value on which condition needs to be checked.
# main.py:
from fastapi import FastAPI, Request
from pydantic import BaseModel
from fastapi.responses import JSONResponse
app = FastAPI()
class UnicornException(Exception):
def __init__(self, value: str):
self.value = value
class Student(BaseModel):
name: str
roll_number: int
students = {
1: Student(name="GK", roll_number=1),
2: Student(name="AK", roll_number=2),
3: Student(name="SB", roll_number=3),
}
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=404,
content={"message": f"Student with particular roll number does not exist."},
)
@app.get("/items/{roll_number}")
async def read_unicorn(roll_number: int):
if roll_number not in students:
raise UnicornException(value=roll_number)
return students[roll_number]
# test.py:
from fastapi.testclient import TestClient

# Assuming the FastAPI app is in a file named main.py
from main import app

# Create a TestClient for the FastAPI app
client = TestClient(app)

# Call the endpoint and print the output
response = client.get("/items/1")
print(response.json())

On calling the function with roll number 1, corresponding to a student in the list, it displays the name and roll number of the student. Conversely, when calling roll number 4, which does not exist in the student list, it shows an error message: “Student with the specified roll number does not exist,” as depicted in the provided screenshot.

Middleware in FastAPI

Middleware in FastAPI refers to a function that operates on every incoming request before processing. This approach showcases error handling in FastAPI through the utilization of middleware.

Syntax:

app.add_middleware(GZipMiddleware)

async def function_name():
if condition:
return f"error_message"

Here,

  • function_name: It is the function which you want to call while testing.
  • condition: It is the check which you want to add to return the error.
  • error_message: It is the message shown to user when there is an error.
# main.py:
from fastapi import FastAPI, Request
from pydantic import BaseModel
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
app.add_middleware(GZipMiddleware)
class Student(BaseModel):
name: str
roll_number: int
students = {
1: Student(name="GK", roll_number=1),
2: Student(name="AK", roll_number=2),
3: Student(name="SB", roll_number=3),
}
@app.get("/items/{roll_number}")
async def query_student_by_roll_number(roll_number: int):
if roll_number not in students:
return (f"Student with {roll_number=} does not exist.")
return students[roll_number]
# test.py:
from fastapi.testclient import TestClient
from main import app

# Create a test client for the FastAPI app
client = TestClient(app)

# Call the function and print the output
response = client.get("/items/1")
print(response.json())

On calling the function with roll number 1, which corresponds to an existing student in the list, it exhibits the name and roll_number details of the student. Conversely, when invoking roll number 4, which is absent in the student list, it showcases a message stating “Student with {roll_number=} does not exist,” as depicted in the provided screenshot.

Logging in FastAPI

Python’s logging module offers essential functions like debug and catch for handling errors. This approach demonstrates how to manage errors in FastAPI by leveraging the capabilities of the logging module.

Syntax:

import logging

logger = logging.getLogger(__name__)

async def function_name():
try:
if condition:
return f"error_message"
return students[roll_number]
except Exception as e:
logger.exception(e)
raise HTTPException(status_code=500, detail="Internal server error")

Here,

  • function_name: It is the function which you want to call while testing.
  • condition: It is the check which you want to add to return the error.
  • error_message: It is the message shown to user when there is an error.
# main.py:
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
import logging
app = FastAPI()
logger = logging.getLogger(__name__)
class Student(BaseModel):
name: str
roll_number: int
students = {
1: Student(name="GK", roll_number=1),
2: Student(name="AK", roll_number=2),
3: Student(name="SB", roll_number=3),
}
@app.get("/items/{roll_number}")
async def query_student_by_roll_number(roll_number: int):
try:
if roll_number not in students:
return (f"Student with {roll_number=} does not exist.")
return students[roll_number]
except Exception as e:
logger.exception(e)
raise HTTPException(status_code=500, detail="Internal server error")
# Test.py:
from fastapi.testclient import TestClient
from test1 import app

# Create a test client for the FastAPI app
client = TestClient(app)

# Call the function and print the output
response = client.get("/items/1")
print(response.json())

On calling the function with roll number 1, which corresponds to an existing student in the list, it exhibits the name and roll_number details of the student. Conversely, when invoking roll number 4, which is absent in the student list, it showcases a message stating “Student with {roll_number=} does not exist,” as depicted in the provided screenshot.

So let’s see how much you’ve retained from the blog

Conclusion:

While we cannot prevent users from executing actions that may lead to errors, our ability lies in effectively managing and addressing those errors. The various techniques outlined in this article empower you to gracefully handle specific errors within FastAPI, ensuring users receive informative feedback about their actions.

In the article we have skimmed through various use cases of FastAPI and various common and important features of it. Happy Learning !!!

Want to take a quiz in case you want to check your level of retainment of the topic, check out now !!!

https://www.bloggpt.actopiagames.com/quizstart/65acf604d98154d19acd72d5

Want to keep me Motivated?

--

--