{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreiamuhlr3rwxyeuayvq5jbtzzwqzjylha3znxy2vov63uhanzyephm",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mpdpbct4t2p2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreie32tt537bq3plmfvgoj3qou7keop5x2q5cb4zvaqa6z56x66zi2q"
},
"mimeType": "image/webp",
"size": 104836
},
"path": "/mihirmohapatra/fastapi-crash-course-build-a-crud-rest-api-in-40-lines-of-python-2m0",
"publishedAt": "2026-06-28T09:38:51.000Z",
"site": "https://dev.to",
"tags": [
"python",
"fastapi",
"webdev",
"beginners",
"View the full source on GitHub",
"github.com/MihirMohapatra/fast-api-example",
"@Valid",
"@RequestBody",
"@app.get",
"@app.post",
"@app.put",
"@app.delete",
"@Data",
"@ResponseBody"
],
"textContent": "> I spend most of my days writing Java and Kotlin for FinTech systems at scale. But every now and then, Python pulls me back in — and FastAPI is exactly the reason why. This is a hands-on crash course based on a project I published on GitHub.\n\n**👉 View the full source on GitHub**\n\n## Why FastAPI?\n\nComing from a Spring Boot background, my first instinct was scepticism. _Another Python framework?_ But FastAPI is genuinely different:\n\n * **Automatic interactive docs** via Swagger UI — no extra config needed\n * **Request validation** powered by Pydantic — think of it as `@Valid` + `@RequestBody` baked in\n * **Type hints as the source of truth** — Python's type system does the heavy lifting\n * **Async-ready** from the ground up — ASGI all the way\n\n\n\nThe best part? You can build a fully working REST API in under 50 lines.\n\n## What We're Building\n\nA **Tea CRUD API** — simple, but covers every REST pattern:\n\nMethod | Endpoint | What It Does\n---|---|---\nGET | `/` | Health / welcome message\nGET | `/teas` | List all teas\nPOST | `/teas` | Add a new tea\nPUT | `/teas/{tea_id}` | Update an existing tea\nDELETE | `/teas/{tea_id}` | Remove a tea\n\nNo database — we're using an in-memory list to keep the focus on FastAPI itself.\n\n## Prerequisites\n\n * Python 3.10+\n * `pip`\n\n\n\nVerify:\n\n\n\n python --version\n pip --version\n\n\n## Setup\n\n**Create and activate a virtual environment:**\n\n\n\n # Windows (PowerShell)\n python -m venv venv\n .\\venv\\Scripts\\Activate\n\n # macOS / Linux\n python3 -m venv venv\n source venv/bin/activate\n\n\n**Install dependencies:**\n\n\n\n pip install \"fastapi[standard]\"\n\n\nThis single command installs FastAPI, Uvicorn (the ASGI server), and all optional extras — all you need to get running.\n\n## The Full Code\n\nCreate a file called `main.py` and drop this in:\n\n\n\n from fastapi import FastAPI\n from pydantic import BaseModel\n from typing import List\n\n app = FastAPI()\n\n class Tea(BaseModel):\n id: int\n name: str\n origin: str\n\n teas: List[Tea] = []\n\n @app.get(\"/\")\n def read_root():\n return {\"message\": \"Welcome to chai code\"}\n\n @app.get(\"/teas\")\n def get_teas():\n return teas\n\n @app.post(\"/teas\")\n def add_teas(tea: Tea):\n teas.append(tea)\n return tea\n\n @app.put(\"/teas/{tea_id}\")\n def update_tea(tea_id: int, update_tea: Tea):\n for index, tea in enumerate(teas):\n if tea.id == tea_id:\n teas[index] = update_tea\n return update_tea\n return {\"error\": \"Tea not found\"}\n\n @app.delete(\"/teas/{tea_id}\")\n def delete_tea(tea_id: int):\n for index, tea in enumerate(teas):\n if tea.id == tea_id:\n deleted = teas.pop(index)\n return deleted\n return {\"error\": \"Tea not found\"}\n\n\nThat's it. 43 lines. Let's break it down.\n\n## Code Walkthrough\n\n### 1. The App Instance\n\n\n app = FastAPI()\n\n\nThis is your application object — equivalent to `new SpringApplication()` in Spring Boot, but in one line with no annotations, XML, or config files.\n\n### 2. The Pydantic Model\n\n\n class Tea(BaseModel):\n id: int\n name: str\n origin: str\n\n\n`BaseModel` from Pydantic is the magic here. Any class that extends it automatically gets:\n\n * **Request body parsing** — FastAPI reads the incoming JSON and maps it to this class\n * **Type validation** — if `id` isn't an integer, FastAPI returns a `422 Unprocessable Entity` with a clear error message\n * **Serialization** — returning a `Tea` instance automatically serializes it to JSON\n\n\n\nFor Java developers: think `@Data` + `@Valid` + `Jackson` — except it's one import and zero annotations on your fields.\n\n### 3. The In-Memory Store\n\n\n teas: List[Tea] = []\n\n\nJust a Python list typed with `List[Tea]`. It acts as our database for this example. Doesn't survive restarts — but that's intentional for a learning project. You'd swap this with SQLAlchemy + PostgreSQL in a production setup.\n\n### 4. GET — List All Teas\n\n\n @app.get(\"/teas\")\n def get_teas():\n return teas\n\n\nReturn the list directly. FastAPI serializes `List[Tea]` to a JSON array automatically. No `ResponseEntity`, no `@ResponseBody`, no boilerplate.\n\n### 5. POST — Add a Tea\n\n\n @app.post(\"/teas\")\n def add_teas(tea: Tea):\n teas.append(tea)\n return tea\n\n\nThe function parameter `tea: Tea` tells FastAPI: _\"expect a JSON body matching the`Tea` schema.\"_ Pydantic validates it. If validation fails, FastAPI returns a detailed 422 error before your function is even called.\n\n### 6. PUT — Update by ID\n\n\n @app.put(\"/teas/{tea_id}\")\n def update_tea(tea_id: int, update_tea: Tea):\n for index, tea in enumerate(teas):\n if tea.id == tea_id:\n teas[index] = update_tea\n return update_tea\n return {\"error\": \"Tea not found\"}\n\n\n`{tea_id}` in the path is a **path parameter** — FastAPI extracts it and coerces it to `int` automatically. You get both a path param (`tea_id`) and a request body (`update_tea`) from a single function signature. Clean.\n\n### 7. DELETE — Remove by ID\n\n\n @app.delete(\"/teas/{tea_id}\")\n def delete_tea(tea_id: int):\n for index, tea in enumerate(teas):\n if tea.id == tea_id:\n deleted = teas.pop(index)\n return deleted\n return {\"error\": \"Tea not found\"}\n\n\nLinear scan through our in-memory list — fine for learning, but you'd index by ID with a dict or use a database in production.\n\n## Run It\n\n\n python -m uvicorn main:app --reload\n\n\nExpected output:\n\n\n\n INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n INFO: Started reloader process\n\n\nThe `--reload` flag means the server restarts automatically on every file save — great for development.\n\n## Interactive API Docs (Free!)\n\nThis is FastAPI's killer feature. Open your browser:\n\nURL | What You Get\n---|---\n`http://127.0.0.1:8000/docs` | Swagger UI — test every endpoint interactively\n`http://127.0.0.1:8000/redoc` | ReDoc — clean, readable API reference\n\nNo extra setup. No Postman required for a quick test. The docs are generated directly from your type hints and Pydantic models.\n\n## Quick Test via Swagger UI\n\n 1. Go to `http://127.0.0.1:8000/docs`\n 2. Click **POST /teas** → **Try it out**\n 3. Paste this body:\n\n\n\n\n {\n \"id\": 1,\n \"name\": \"Assam Tea\",\n \"origin\": \"India\"\n }\n\n\n 1. Click **Execute**\n 2. Now hit **GET /teas** — you'll see your tea in the list\n\n\n\n## What's Next (Production Roadmap)\n\nThis in-memory app is intentionally minimal. Here's how you'd evolve it toward production:\n\nConcern | Tool\n---|---\nPersistent storage | SQLAlchemy + PostgreSQL or SQLite\nMigrations | Alembic\nAuth | JWT via `python-jose` + `passlib`\nDependency Injection | FastAPI's built-in `Depends()` system\nEnvironment config | `pydantic-settings`\nContainerization | Docker + `uvicorn` in production mode\nTesting | `pytest` + `httpx` (async test client)\nAsync DB | `asyncpg` + SQLAlchemy async sessions\n\n## Java/Kotlin Developer Take\n\nHaving spent years with Spring Boot, here's my honest comparison:\n\n**FastAPI wins on:**\n\n * Speed of prototyping — no boilerplate ceremony\n * Auto-generated docs that are actually useful\n * Cleaner validation without annotation overload\n\n\n\n**Spring Boot still wins on:**\n\n * Enterprise ecosystem maturity\n * Structured DI with complex bean graphs\n * Mature monitoring (Actuator, Micrometer)\n\n\n\nFastAPI fills a real gap: it's the right tool when you want Python's data ecosystem (ML, data pipelines) behind a production-quality HTTP API. The two aren't in competition — they're tools for different contexts.\n\n## Source Code\n\nEverything in this post is available here:\n\n**github.com/MihirMohapatra/fast-api-example**\n\nDrop a ⭐ if it helped you get started.\n\n_Building toward senior remote roles at US/EU companies. Follow along as I explore FastAPI, Rust, Go, and AI infrastructure — writing from the perspective of a practising backend engineer, not a tutorial blog._",
"title": "FastAPI Crash Course: Build a CRUD REST API in ~40 Lines of Python"
}