FastAPI Tutorial: Building Your First REST API in 30 Minutes
A hands-on FastAPI tutorial for beginners: build a fully functional REST API in 30 minutes with CRUD endpoints, request validation, and automatic docs.
Get more content like this on Telegram!
Daily AI tips, notes & resources — free
FastAPI Tutorial: Building Your First REST API in 30 Minutes
When I discovered FastAPI after months of Flask and Django, my first reaction was "why didn't I start here?"
FastAPI does something no other Python framework does as well: it makes building an API feel effortless without hiding what's happening. You write Python functions. You add type hints. FastAPI turns those into a fully documented, validated API automatically.
This tutorial will have you running a real REST API with full documentation in 30 minutes. No prior API experience needed — just Python fundamentals.
What We're Building
A task management API with full CRUD operations:
GET /tasks— list all tasksPOST /tasks— create a taskGET /tasks/{id}— get one taskPUT /tasks/{id}— update a taskDELETE /tasks/{id}— delete a task
By the end, you'll have an API running with automatic documentation at /docs. You can test every endpoint without writing any frontend code.
Setup (5 Minutes)
1. Create a virtual environment
mkdir task-api
cd task-api
python -m venv venv
source venv/bin/activate # Mac/Linux
# OR
venv\Scripts\activate # Windows
2. Install FastAPI
pip install fastapi uvicorn
That's it. No database setup yet — we'll start with in-memory storage so nothing gets in the way of learning the API concepts.
3. Create main.py
Create a file called main.py in your project folder. This is where everything goes.
Your First FastAPI Endpoint (5 Minutes)
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Task API is running"}
Run it:
uvicorn main:app --reload
Open http://localhost:8000 — you should see {"message": "Task API is running"}.
Open http://localhost:8000/docs — you'll see the Swagger UI showing your endpoint, completely automatically generated. This is one of FastAPI's best features.
What just happened: @app.get("/") is a decorator that registers the function as a GET endpoint at the "/" path. The function returns a Python dict; FastAPI converts it to JSON automatically.
Adding Data Models with Pydantic (5 Minutes)
FastAPI uses Pydantic for data validation. You define the shape of your data as a class, and FastAPI validates all incoming requests against it automatically.
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
app = FastAPI()
class Task(BaseModel):
id: int
title: str
description: Optional[str] = None
completed: bool = False
created_at: datetime = datetime.now()
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
Two models:
Task— the full task object (what we return from the API)TaskCreate— what the client sends to create a task (no id, no created_at — those are generated server-side)
In-Memory Storage
For this tutorial, we'll store tasks in a Python list. In a real app, you'd use a database.
# Storage (in-memory — resets when server restarts)
tasks_db: list[Task] = []
next_id = 1
The CRUD Endpoints (10 Minutes)
GET /tasks — List All Tasks
@app.get("/tasks", response_model=list[Task])
def get_tasks():
return tasks_db
The response_model=list[Task] tells FastAPI what the response shape looks like — it uses this for documentation and to filter any extra fields.
POST /tasks — Create a Task
@app.post("/tasks", response_model=Task, status_code=201)
def create_task(task_data: TaskCreate):
global next_id
task = Task(
id=next_id,
title=task_data.title,
description=task_data.description,
)
tasks_db.append(task)
next_id += 1
return task
FastAPI automatically validates that the request body matches TaskCreate. If the client sends invalid data (missing title, wrong types), FastAPI returns a 422 error with a clear explanation — no custom validation code required.
GET /tasks/ — Get One Task
from fastapi import FastAPI, HTTPException
@app.get("/tasks/{task_id}", response_model=Task)
def get_task(task_id: int):
for task in tasks_db:
if task.id == task_id:
return task
raise HTTPException(status_code=404, detail="Task not found")
{task_id} in the path is a path parameter. FastAPI automatically converts it to int and validates it.
PUT /tasks/ — Update a Task
class TaskUpdate(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
completed: Optional[bool] = None
@app.put("/tasks/{task_id}", response_model=Task)
def update_task(task_id: int, updates: TaskUpdate):
for task in tasks_db:
if task.id == task_id:
if updates.title is not None:
task.title = updates.title
if updates.description is not None:
task.description = updates.description
if updates.completed is not None:
task.completed = updates.completed
return task
raise HTTPException(status_code=404, detail="Task not found")
DELETE /tasks/ — Delete a Task
@app.delete("/tasks/{task_id}", status_code=204)
def delete_task(task_id: int):
for i, task in enumerate(tasks_db):
if task.id == task_id:
tasks_db.pop(i)
return
raise HTTPException(status_code=404, detail="Task not found")
The Complete main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
app = FastAPI(title="Task API", description="A simple task management API")
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
class TaskUpdate(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
completed: Optional[bool] = None
class Task(BaseModel):
id: int
title: str
description: Optional[str] = None
completed: bool = False
created_at: str = ""
tasks_db: list[Task] = []
next_id = 1
@app.get("/")
def read_root():
return {"message": "Task API", "docs": "/docs"}
@app.get("/tasks", response_model=list[Task])
def get_tasks():
return tasks_db
@app.post("/tasks", response_model=Task, status_code=201)
def create_task(task_data: TaskCreate):
global next_id
task = Task(
id=next_id,
title=task_data.title,
description=task_data.description,
created_at=datetime.now().isoformat(),
)
tasks_db.append(task)
next_id += 1
return task
@app.get("/tasks/{task_id}", response_model=Task)
def get_task(task_id: int):
for task in tasks_db:
if task.id == task_id:
return task
raise HTTPException(status_code=404, detail="Task not found")
@app.put("/tasks/{task_id}", response_model=Task)
def update_task(task_id: int, updates: TaskUpdate):
for task in tasks_db:
if task.id == task_id:
if updates.title is not None:
task.title = updates.title
if updates.description is not None:
task.description = updates.description
if updates.completed is not None:
task.completed = updates.completed
return task
raise HTTPException(status_code=404, detail="Task not found")
@app.delete("/tasks/{task_id}", status_code=204)
def delete_task(task_id: int):
for i, task in enumerate(tasks_db):
if task.id == task_id:
tasks_db.pop(i)
return
raise HTTPException(status_code=404, detail="Task not found")
Testing Your API (5 Minutes)
Open http://localhost:8000/docs. You'll see the full Swagger UI. Click any endpoint, click "Try it out," fill in the form, and execute. No Postman required.
Testing sequence:
POST /taskswith{"title": "Learn FastAPI"}— should return the created taskGET /tasks— should show your task in a listPUT /tasks/1with{"completed": true}— should mark it doneDELETE /tasks/1— should remove itGET /tasks/1— should return 404
Next Steps After This Tutorial
Add a real database: Replace in-memory storage with SQLite + SQLAlchemy. The FastAPI documentation has an excellent SQL databases tutorial.
Add authentication: Add JWT token authentication so only logged-in users can manage their tasks. This turns the tutorial project into a portfolio piece.
Deploy it: Push to GitHub, connect to Railway or Render, and deploy for free. A live URL makes this a proper portfolio project.
For the portfolio context and what to build next, see our guide on Python projects that get you a developer job.
For a comparison of FastAPI vs. Django for larger projects, our Django vs. Flask guide covers when to choose each framework.
Frequently Asked Questions
What is FastAPI?
A modern Python framework for building APIs with automatic documentation, request validation, and async support. One of the fastest Python frameworks.
FastAPI vs. Django REST Framework?
FastAPI for new API-only projects. Django + DRF for full web apps or teams with existing Django expertise.
How do I deploy FastAPI?
Railway or Render (free tier) for beginners. Add requirements.txt, set start command to uvicorn main:app --host 0.0.0.0 --port $PORT, connect GitHub repo.
Does FastAPI support databases?
Yes — SQLAlchemy, Tortoise-ORM, SQLModel, and any Python database library.
Final Thoughts
In 30 minutes, you've built a real REST API with five endpoints, automatic documentation, and request validation. That's the FastAPI experience — get productive immediately, without the boilerplate that slows down other frameworks.
This tutorial project is a solid foundation for a portfolio piece. Add authentication, a database, and deploy it, and you have exactly the kind of project that gets interviews.
For learning about the Python requests library to call APIs like this one from other scripts, see our Python requests library guide. And to continue with data handling and OOP patterns, our Python OOP tutorial builds the class-based patterns you'll use in larger FastAPI apps.
Frequently Asked Questions
AiTechWorlds Team
✓ Verified WriterThe AiTechWorlds team is passionate about AI, technology, and education. We create high-quality, research-backed content to help you learn, grow, and succeed in the modern digital world.
Related Articles
The Python Libraries Every Developer Must Know in 2025
The essential Python libraries for 2025: from requests and pandas to FastAPI and LangChain — what each does, when to use it, and how to get started quickly.
Django vs Flask in 2025: Which Framework Should You Learn?
An honest Django vs Flask comparison for 2025 — which Python framework to learn first, when each excels, and why FastAPI has changed the equation.
Jupyter Notebook Guide: The Data Scientist's Favorite Tool
A complete Jupyter Notebook guide for 2025: installation, essential shortcuts, best practices, and how data scientists use Jupyter for exploration, analysis, and sharing.
How I Learned Python in 3 Months and Got a Job: My Honest Story
A real story of learning Python fast and landing a developer job in 90 days — what worked, what failed, and the exact roadmap to learn Python quickly.