FastAPI Interview Questions 26-30 (Security, CORS, & Exceptions)
We are entering the deployment and security phase of your preparation. These are the questions that separate a hobbyist from a developer who can put code into production.
We will cover how to handle user logins securely (OAuth2), how to fix that annoying CORS error your frontend developer keeps complaining about, and how to ensure your API fails gracefully instead of crashing with a 500 error. Finally, we will touch on the gold standard for Python databases: SQLAlchemy.
26. How do you use Form data and OAuth2 form inputs?
JSON is great for APIs, but sometimes you need to send data using HTML forms (application/x-www-form-urlencoded), especially for login pages. FastAPI has a specific dependency for this.
For login flows specifically, FastAPI provides OAuth2PasswordRequestForm. This is a ready-made class that expects a username and passwordfield in the form data.
from fastapi import FastAPI, Depends, Form
from fastapi.security import OAuth2PasswordRequestForm
app = FastAPI()
# 1. Basic Form Data
@app.post("/login-basic/")
def login_basic(username: str = Form(), password: str = Form()):
return {"username": username}
# 2. Standard OAuth2 Form (Recommended for Auth)
@app.post("/token")
def login_oauth(form_data: OAuth2PasswordRequestForm = Depends()):
# form_data.username & form_data.password are automatically extracted
return {
"access_token": form_data.username + "token",
"token_type": "bearer"
}
Sample Output:
If you send a POST request with form data username=alice&password=secret:
{
"access_token": "alicetoken",
"token_type": "bearer"
}27. How does FastAPI handle CORS and how do you configure it?
CORS (Cross-Origin Resource Sharing) is a browser security feature. It blocks a frontend running on localhost:3000 (React/Vue) from calling a backend onlocalhost:8000 (FastAPI) unless the backend explicitly allows it.
To fix this, you use the CORSMiddleware. You must configure it to allow specific origins.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost:3000", # React App
"https://myapp.com", # Production Domain
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # List of allowed domains
allow_credentials=True, # Allow cookies/auth headers
allow_methods=["*"], # Allow all methods (GET, POST, etc.)
allow_headers=["*"], # Allow all headers
)
@app.get("/")
def main():
return {"message": "CORS is fixed!"}
Warning: Never use allow_origins=["*"]in production if your app involves authentication (cookies/headers). It is a security risk. Always list specific domains.
28. What are HTTPException and custom exception handlers?
You should not let your code crash with a Python error (like KeyError orZeroDivisionError) because it returns a 500 Internal Server Error, which looks unprofessional and hides the real issue from the client.
Instead, you should raise an HTTPException to return a controlled JSON error response.
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {"a": "Foo", "b": "Bar"}
@app.get("/items/{item_id}")
def read_item(item_id: str):
if item_id not in items:
# Stop execution and return 404 immediately
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}
Sample Output (for /items/z):
{
"detail": "Item not found"
}29. How do you add global exception handling?
Sometimes, you want to catch all errors of a certain type globally, so you don't have to write try/except blocks in every single function. For example, you might want to catch a custom BusinessLogicError everywhere.
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
# 1. Define a custom Python exception
class UnicornException(Exception):
def __init__(self, name: str):
self.name = name
app = FastAPI()
# 2. Register a global handler for it
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418, # I'm a teapot
content={"message": f"Oops! {exc.name} did something wrong."},
)
@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
if name == "yolo":
# Just raise the Python exception normally
raise UnicornException(name=name)
return {"unicorn_name": name}
Sample Output (for /unicorns/yolo):
{
"message": "Oops! yolo did something wrong."
}Status code will be 418.
30. How do you integrate SQL databases with FastAPI using SQLAlchemy?
This is a large topic, but for an interview, you need to know the architectural flow. FastAPI does not have a built-in ORM like Django. You have to wire it up yourself. The standard stack is SQLAlchemy (ORM) +Pydantic (Validation).
The 3-Layer Pattern:
- 1. Database Model (SQLAlchemy): Represents the table structure in the DB.
- 2. Pydantic Schema: Represents the JSON data sent/received by the API.
- 3. CRUD Function: Reads from DB Model and converts to Pydantic Schema.
# 1. Setup (database.py)
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()
# 2. The DB Model
class UserDB(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
Base.metadata.create_all(bind=engine)
# 3. The API (main.py)
from fastapi import FastAPI, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session
app = FastAPI()
# Pydantic Schema
class UserSchema(BaseModel):
email: str
class Config:
orm_mode = True # Allows Pydantic to read SQLAlchemy objects
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/users/", response_model=UserSchema)
def create_user(user: UserSchema, db: Session = Depends(get_db)):
# Create DB object
db_user = UserDB(email=user.email)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user # Returns SQLAlchemy object, converted to JSON by Pydantic
Sample Output:
{
"email": "newuser@example.com"
}