What are Type Hints?
Type hints let you tell Python what type of data a variable or function expects.
# Without type hints def add(a, b): return a + b
# With type hints def add(a: int, b: int) -> int: return a + b
The : int after each parameter says "this should be an integer". The -> int says "this function returns an integer".
Important Thing to Understand
Type hints in Python are not enforced at runtime. Python won't throw an error if you pass a string where you said int. They are hints — for you, your editor, and tools like FastAPI.
def add(a: int, b: int) -> int: return a + b
add(5, 3) # correct usage add("hi", "yo") # Python won't crash — but your editor will warn you
FastAPI however does enforce them — it uses type hints to validate incoming data automatically. That's one of its superpowers.
Variable Type Hints
name: str = "Gagan" age: int = 22 height: float = 5.11 is_student: bool = True
You'll rarely type hint simple variables. More common in function parameters and return types.
Function Type Hints
def greet(name: str) -> str: return f"Hello, {name}!"
def calculate_area(length: float, width: float) -> float: return length * width
def is_adult(age: int) -> bool: return age >= 18
def print_info(name: str, age: int) -> None: # None means returns nothing print(f"{name} is {age} years old")
Type Hints for Collections
from typing import List, Dict, Tuple, Set
# List of strings def greet_all(names: List[str]) -> None: for name in names: print(f"Hello {name}")
# Dictionary def get_user_info(user: Dict[str, str]) -> str: return user["name"]
# List of integers def get_average(marks: List[int]) -> float: return sum(marks) / len(marks)
In Python 3.9+ you can use lowercase directly:
# Modern way — Python 3.9+ def greet_all(names: list[str]) -> None: for name in names: print(f"Hello {name}")
def get_scores(data: dict[str, int]) -> list[int]: return list(data.values())
Since you're using Python 3.13 — always use the modern lowercase style.
Optional — Value That Might Be None
Very common in APIs — some fields are optional:
from typing import Optional
# Old way def greet(name: str, title: Optional[str] = None) -> str: if title: return f"Hello, {title} {name}!" return f"Hello, {name}!"
# Modern way — Python 3.10+ def greet(name: str, title: str | None = None) -> str: if title: return f"Hello, {title} {name}!" return f"Hello, {name}!"
print(greet("Gagan")) # Hello, Gagan! print(greet("Gagan", "Mr.")) # Hello, Mr. Gagan!
str | None means "either a string or None". This is the modern Python 3.10+ syntax. Use this.
Union — Multiple Possible Types
# Old way from typing import Union def process(value: Union[int, str]) -> str: return str(value)
# Modern way — Python 3.10+ def process(value: int | str) -> str: return str(value)
Type Hints with Classes
class Student: def __init__(self, name: str, age: int, marks: list[int]) -> None: self.name = name self.age = age self.marks = marks
def get_average(self) -> float: return sum(self.marks) / len(self.marks)
def is_passing(self) -> bool: return self.get_average() >= 50
def __str__(self) -> str: return f"Student({self.name}, avg={self.get_average():.1f})"
def print_student(student: Student) -> None: print(student)
s = Student("Gagan", 22, [85, 90, 78]) print_student(s)
Quick Reference — Type Hints Cheat Sheet
# Basic types
name: str
age: int
price: float
active: bool
# Collections
items: list[str]
scores: dict[str, int]
coordinates: tuple[float, float]
unique_ids: set[int]
# Optional (might be None)
nickname: str | None = None
# Union (multiple types)
value: int | str
# Function return types
def get_name() -> str: ...
def process() -> None: ...
def get_data() -> list[dict[str, int]]: ...
Exercise — Rewrite with Type Hints
Take this existing code and add proper type hints:
def calculate_bill(items, tax_rate): subtotal = sum(items) tax = subtotal * tax_rate total = subtotal + tax return total
def get_student_info(name, age, marks): average = sum(marks) / len(marks) return {"name": name, "age": age, "average": average}
def find_passing_students(students): return [s for s in students if s["average"] >= 50]
Expected answer:
def calculate_bill(items: list[float], tax_rate: float) -> float: subtotal = sum(items) tax = subtotal * tax_rate total = subtotal + tax return total
def get_student_info(name: str, age: int, marks: list[int]) -> dict[str, int | float | str]: average = sum(marks) / len(marks) return {"name": name, "age": age, "average": average}
def find_passing_students(students: list[dict]) -> list[dict]: return [s for s in students if s["average"] >= 50]
Step 2: Virtual Environments
What is a Virtual Environment?
Every Python project needs different libraries and versions. Without virtual environments, all libraries install globally — projects start conflicting with each other.
Think of it like this:
Project A needs requests version 2.28
Project B needs requests version 2.31
Without venv — only one version installed globally — one project breaks
With venv — each project has its own isolated Python environment
Virtual environment = isolated Python installation for each project.
This is standard practice — every professional Python project uses one.
Creating a Virtual Environment
Open terminal in your project folder:
# Create virtual environment named 'venv'
python -m venv venv
This creates a venv folder in your project directory containing an isolated Python installation.
On Mac/Linux:
python3 -m venv venv
Activating the Virtual Environment
Windows:
venv\Scripts\activate
Mac/Linux:
source venv/bin/activate
After activation your terminal prompt changes:
(venv) C:\Users\Gagan\my-project>
The (venv) prefix tells you the virtual environment is active. Now any pip install goes into this project only — not globally.
Deactivating
deactivate
Prompt goes back to normal. You're back to global Python.
.gitignore — Never Commit venv
The venv folder is huge (thousands of files). Never commit it to git. Add it to .gitignore:
venv/
__pycache__/
*.pyc
.env
Instead commit requirements.txt so anyone can recreate the environment:
# Save all installed packages
pip freeze > requirements.txt
# Anyone else installs everything with
pip install -r requirements.txt
VS Code — Select Virtual Environment
After creating venv, tell VS Code to use it:
- Press
Ctrl + Shift + P - Type "Python: Select Interpreter"
- Choose the one that shows
venvin the path
VS Code will now use your virtual environment automatically.
Step 3: Installing FastAPI
Now let's set up a real FastAPI project from scratch.
Create Project Folder
mkdir fastapi-learning
cd fastapi-learning
Create and Activate Virtual Environment
python -m venv venv
# Windows
venv\Scripts\activate
# Mac/Linux
source venv/bin/activate
Install FastAPI and Uvicorn
pip install fastapi uvicorn
FastAPI — the framework itself. Uvicorn — the server that runs your FastAPI app. Think of it like Nodemon in Node.js world.
Wait for installation to complete. Then verify:
pip show fastapi
pip show uvicorn
You should see version info for both.
Your First FastAPI App
Create a file called main.py inside your project folder:
from fastapi import FastAPI
app = FastAPI()
@app.get("/") def read_root(): return {"message": "Hello, World!"}
@app.get("/hello/{name}") def say_hello(name: str): return {"message": f"Hello, {name}!"}
That's it. A complete running API in 8 lines.
Running the Server
uvicorn main:app --reload
Breaking this down:
main— your filename (main.py)app— the FastAPI instance variable name--reload— auto restart when you save changes (like nodemon)
You'll see:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process
INFO: Started server process
INFO: Waiting for application startup.
INFO: Application startup complete.
Your API is running at http://localhost:8000
Testing Your First API
Open your browser and visit:
http://localhost:8000
{"message": "Hello, World!"}
http://localhost:8000/hello/Gagan
{"message": "Hello, Gagan!"}
It works. You just built and ran your first API with FastAPI.
Free Automatic Documentation — The Magic
This is one of FastAPI's biggest features. Visit:
http://localhost:8000/docs
You'll see a beautiful interactive API documentation page — Swagger UI — automatically generated from your code. No extra work.
You can:
- See all your routes
- Test them directly from the browser
- See request/response formats
Also available at:
http://localhost:8000/redoc
A different documentation style — cleaner for reading.
This is automatically updated every time you add a new route. In NestJS you had to manually setup Swagger — here it's built in and zero config.
Understanding the Code
Let's break down main.py line by line:
from fastapi import FastAPI
Import the FastAPI class.
app = FastAPI()
Create the FastAPI application instance. This is your entire app.
@app.get("/")
This is a decorator — it registers the function below as a GET route at path /.
def read_root(): return {"message": "Hello, World!"}
The route handler function. Whatever you return — FastAPI automatically converts it to JSON response.
@app.get("/hello/{name}") def say_hello(name: str):
{name} in the path is a path parameter. FastAPI reads it and passes it to the function. The : str type hint tells FastAPI to validate it's a string.
Adding More to Your App
Update main.py and save — server auto-reloads:
from fastapi import FastAPIapp = FastAPI(title="My First FastAPI",description="Learning FastAPI step by step",version="1.0.0")@app.get("/")def read_root():return {"message": "Hello, World!", "status": "running"}@app.get("/hello/{name}")def say_hello(name: str):return {"message": f"Hello, {name}!"}@app.get("/add/{a}/{b}")def add_numbers(a: int, b: int):return {"a": a,"b": b,"sum": a + b}@app.get("/info")def get_info():return {"framework": "FastAPI","language": "Python","version": "1.0.0","developer": "Gagan"}
Visit /docs again — you'll see all 4 routes documented automatically.
Visit /add/10/25:
{"a": 10, "b": 25, "sum": 35}
FastAPI automatically converted "10" and "25" from the URL string into integers because of the : int type hints. That's the power of type hints in FastAPI.
Project Structure So Far
fastapi-learning/
├── venv/ ← virtual environment (don't touch)
├── main.py ← your app
└── requirements.txt ← after pip freeze
Simple for now. Will grow as we add more features.
Summary of What You Learned
In this stage you covered:
- Python type hints — basic and modern syntax
- Virtual environments — why and how to use them
- Installing FastAPI and Uvicorn
- Creating and running your first FastAPI app
- Automatic documentation at
/docs - Path parameters with type validation
No comments:
Post a Comment