FastAPI Tutorial: Building Your First REST API in 30 Minutes
โก Quick Answer
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
Advertisement
FastAPI Tutorial: Building Your First REST API in 30 Minutes
FastAPI is a Python framework that turns type-hinted functions into a fully validated, self-documenting REST API โ no separate schema files, no manual request parsing. Write a function, annotate the types, and the framework does the rest.
This tutorial gets a real REST API running with full interactive 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 # Windows2. Install FastAPI
pip install fastapi uvicornThat'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 --reloadOpen 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 โ like a customs checkpoint that inspects every request before it's allowed into your code. 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] = NoneTwo 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 = 1The CRUD Endpoints (10 Minutes)
GET /tasks โ List All Tasks
@app.get("/tasks", response_model=list[Task])
def get_tasks():
return tasks_dbThe 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 taskFastAPI 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, not just local-only code.
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.
Further Reading
- Python OOP Complete Guide 2026 โ Object-Oriented Programming Mastery
- Deploying Python Apps to AWS: A Complete Beginner's Guide
- Jupyter Notebook Guide: The Data Scientist's Favorite Tool
- FastAPI Tutorial 2026 โ Build Production-Ready REST APIs with Python
- Python for Beginners: Complete 2026 Roadmap โ Step-by-Step Guide
- Deploy AI Model to Production: FastAPI, Docker, and Cloud Deployment Guide
- Terminal and Command Line Mastery: 30 Commands That Changed My Life
- Best Machine Learning Courses in 2025: Ranked After Taking Them All
Advertisement
๐ฌ DiscussionPowered by GitHub Discussions
Frequently Asked Questions
Problem Solver and Cloud Expert
Solves complex infrastructure challenges and architects reliable, scalable cloud deployments for every project. Shamshur Rahman keeps AiTechWorldsโ hosting and cloud infrastructure fast, resilient, and cost-efficient.
Not sure yet? Ask AI about this article
Get an instant, unbiased AI summary of โFastAPI Tutorial: Building Your First REST API in 30 Minutesโ.
Advertisement
Related Articles
The Python Libraries Every Developer Must Know in 2026
The essential Python libraries for 2026: 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 2026: Which Framework Should You Learn?
An honest Django vs Flask comparison for 2026 โ 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 2026: 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.