How to Create REST APIs in Python using FastAPI (Step-by-Step Guide)


Building APIs in Python has never been easier thanks to FastAPI. It’s modern, fast (high-performance), and super-friendly for developers — especially if you're already comfortable with Python.
In this guide, we’ll build a practical Product API — nothing generic, just clear and useful examples.
Topics Covered
What is FastAPI
How to install it
Build your first API (GET, POST, PUT, DELETE)
How to validate input using Pydantic
Try the API with Swagger UI
Recommended project structure
Final full code for reference
🧠 What is FastAPI?
FastAPI is a modern Python web framework designed for building APIs with:
Built-in data validation using Pydantic
Automatic documentation (Swagger/OpenAPI)
Type hints for clean code
Async support
Super performance (comparable to Node.js and Go)
Step 1: Install FastAPI and Uvicorn
To use FastAPI, you need to install it first. You also install Uvicorn, which is like a mini server to run your API.
Just type this in your terminal:
pip install fastapi uvicorn
fastapi
: The main frameworkuvicorn
: A fast server to run your FastAPI app
Step 2: Create a Simple API
Let’s build a real-world example: Product Management API
You start by creating a file (e.g., main.py
) and write some code that tells the computer what to do when someone visits certain links (like /products
).
You use
@app.get()
to handle read requests.You write a simple dictionary to store some product data.
You return that data when someone visits
/products
.
File: main.py
from fastapi import FastAPI
app = FastAPI()
# In-memory data storage (for simplicity)
products = {
1: {"name": "Laptop", "price": 75000},
2: {"name": "Smartphone", "price": 30000}
}
@app.get("/")
def home():
return {"message": "Welcome to Product API"}
@app.get("/products")
def get_all_products():
return products
@app.get("/products/{product_id}")
def get_product(product_id: int):
if product_id in products:
return products[product_id]
return {"error": "Product not found"}
Run Your Server
Run this in terminal:
uvicorn main:app --reload
Now visit: http://127.0.0.1:8000/docs
🎉 You’ll see a beautiful Swagger UI to test your API.
Step 3: Add POST (Create Product)
To allow creating products, we need to accept input data and validate it.
To allow users to add a new product, you need to:
Accept user input
Make sure it's valid (like name and price are provided)
Save it
You use something called a Pydantic
model (like a form) to check that the input is correct.
Create a Pydantic model:
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
Add a POST endpoint:
@app.post("/products")
def create_product(product: Product):
new_id = max(products.keys()) + 1 if products else 1
products[new_id] = product.dict()
return {"id": new_id, "product": products[new_id]}
product.dict()
converts the Pydantic model into a normal Python dict.
Step 4: Add PUT (Update Product)
This lets users update a product that already exists.
It checks if the product exists.
If it does, it updates the name and price.
If it doesn’t, it shows an error message.
@app.put("/products/{product_id}")
def update_product(product_id: int, product: Product):
if product_id not in products:
return {"error": "Product not found"}
products[product_id] = product.dict()
return {"message": "Product updated", "product": products[product_id]}
Step 5: Add DELETE (Remove Product)
This lets users delete a product using its ID.
It checks if the product exists.
If yes, it removes it and returns a success message.
If no, it returns an error.
@app.delete("/products/{product_id}")
def delete_product(product_id: int):
if product_id in products:
deleted = products.pop(product_id)
return {"message": "Product deleted", "product": deleted}
return {"error": "Product not found"}
Step 6: Try It in Swagger UI
Visit:
🌐 Docs: http://127.0.0.1:8000/docs
📃 Redoc: http://127.0.0.1:8000/redoc
You can test all your endpoints in the browser — no Postman needed.
Once your server is running, you can open http://127.0.0.1:8000/docs in your browser.
It shows all your API routes.
You can test everything (GET, POST, PUT,DELETE) without writing any code.
Recommended Folder Structure
As your project grows, it’s better to keep your files organized.
Keep models (data structures) in
models.py
Keep all routes (endpoints) in
routes.py
Put everything in an
app/
folderImport these into your main app (
main.py
) to run everything together
When your app grows, split it into modules:
.
├── app
│ ├── main.py
│ ├── models.py
│ ├── routes.py
│ └── database.py (optional)
└── requirements.txt
Example: models.py
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
Example: routes.py
from fastapi import APIRouter
from .models import Product
router = APIRouter()
products = {}
@router.post("/products")
def create_product(product: Product):
...
Then in main.py
:
from fastapi import FastAPI
from app.routes import router
app = FastAPI()
app.include_router(router)
Full Final Code
Here’s the complete working code in one file for reference:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
products = {
1: {"name": "Laptop", "price": 75000},
2: {"name": "Smartphone", "price": 30000}
}
class Product(BaseModel):
name: str
price: float
@app.get("/")
def home():
return {"message": "Welcome to Product API"}
@app.get("/products")
def get_all_products():
return products
@app.get("/products/{product_id}")
def get_product(product_id: int):
return products.get(product_id, {"error": "Product not found"})
@app.post("/products")
def create_product(product: Product):
new_id = max(products.keys()) + 1 if products else 1
products[new_id] = product.dict()
return {"id": new_id, "product": products[new_id]}
@app.put("/products/{product_id}")
def update_product(product_id: int, product: Product):
if product_id not in products:
return {"error": "Product not found"}
products[product_id] = product.dict()
return {"message": "Product updated", "product": products[product_id]}
@app.delete("/products/{product_id}")
def delete_product(product_id: int):
if product_id in products:
deleted = products.pop(product_id)
return {"message": "Product deleted", "product": deleted}
return {"error": "Product not found"}
Wrapping Up
FastAPI is powerful but easy to use. We just built a complete REST API with:
✅ Type-safe request/response
✅ Input validation using Pydantic
✅ Full CRUD support
✅ Swagger docs auto-generated
✅ No extra setup needed
Subscribe to my newsletter
Read articles from Shaik Sameer directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
