Learning Python & FastAPI in a Week
One week. That's how long it took me to learn enough Python to build the backend of this project.
I know that sounds either impressive or reckless depending on your perspective. But here's the thing — I wasn't learning programming from scratch. I've been writing PHP for years. I know what a variable is, what a function does, how HTTP works. What I didn't know was Python's syntax, its ecosystem, and its conventions.
PHP Brain Meets Python
Photo by Ecliptic Graphic on Unsplash
Let me be honest about something: Python frustrated me. Not because it's bad — but because coming from PHP, everything felt subtly wrong. Here's what got under my skin:
Environment Setup Chaos
In PHP, you install it, you run it, it works. Python? You need a virtual environment. You need to activate it. You need to manage .env files, path variables, and system Python vs project Python. I used base Python — no uv, no poetry, no conda — and just navigating virtual environments and understanding why my installed packages weren't being found took an embarrassing amount of time before I wrote a single line of code.
No Curly Braces
In PHP, you have { }. Blocks of code are visually clear. You can see where a function starts and ends. Python? You get indentation. Forget a tab or mix spaces and tabs and your code breaks with an error that makes you question your life choices. My fingers kept wanting to type a closing brace at the end of every block. They still do.
// PHP: Explicit braces, dollar sigils
function formatMessage(string $user, string $msg): string {
if (!empty($msg)) {
return "{$user}: " . trim($msg);
}
return "";
}
# Python: Indentation-based scope, no braces
def format_message(user: str, msg: str) -> str:
if msg:
return f"{user}: {msg.strip()}"
return ""
Implicit Variable Creation
In PHP, variables start with $. You always know when you're creating or referencing one. Python just... lets you create a variable by assigning to it. No declaration, no sigil, no ceremony. Sounds nice until you misspell a variable name and Python happily creates a new one instead of throwing an error. Silent bugs, the worst kind.
Namespace Chaos
PHP has namespaces and autoloading. It's predictable. Python's import system felt like the wild west by comparison. Modules, packages, __init__.py files, relative imports, absolute imports — I'd write an import that worked in one file and failed in another for reasons that took me way too long to understand. Half my errors during that first week were import-related.
Why FastAPI
Photo by Mohammad Rahmani on Unsplash
I chose FastAPI for one simple reason: I only needed an API.
In PHP, I'd use something slim — maybe a microframework. I didn't want Django's overhead. I didn't want templates, admin panels, or a batteries-included framework. I just needed something that could receive HTTP requests, talk to a database, and stream responses from an LLM API.
FastAPI delivered exactly that. The name isn't lying — it's fast to set up, and it's an API. Within a day of learning, I had endpoints running.
The Learning Curve
Photo by Luella Wong on Unsplash
Here's what I had to pick up in that week:
- Python basics — syntax, types, decorators, async/await
- FastAPI — routing, dependency injection, request/response models
- Pydantic — validation schemas that FastAPI uses under the hood
- SQLAlchemy — the ORM. Coming from raw SQL queries in PHP, this was a mindset shift
- Alembic — database migrations. I'd never used migrations before, so this was new regardless of language
Async was the biggest conceptual leap. In PHP, everything is synchronous. You make a request, you wait, you get a response. In FastAPI, you use async and await to handle concurrent operations. It took me a while to understand when to use async and when not to — and honestly, I'm still not sure I always get it right.
How I Structured the Backend
Photo by Ferenc Almasi on Unsplash
I went with a layered architecture because it's what made sense to me:
- Models — SQLAlchemy models defining database tables (User, ChatModel, Feedback)
- Schemas — Pydantic models for request validation and response serialization
- Services — Business logic lives here. The chat service orchestrates LLM calls, the user service handles CRUD, etc.
- Endpoints — Thin route handlers that call services and return responses
This separation felt natural coming from PHP where I was used to keeping database logic separate from routing. Clean, predictable, easy to navigate.
# Pydantic schema for request validation
from pydantic import BaseModel, Field
class ChatRequest(BaseModel):
character_id: str
message: str = Field(..., min_length=1)
temperature: float = Field(default=0.7, ge=0.0, le=2.0)
top_p: float = Field(default=1.0, ge=0.0, le=1.0)
AI Tools: Great Starter, Bad Finisher
Photo by Andrey Khoviakov on Unsplash
I used opencode to help write the initial boilerplate, and here's my honest take: AI coding tools are incredible for getting you started and terrible at actual implementation.
Boilerplate code? Scaffolding? Project structure? Setting up configs? They're fast. They'll generate your base models, your initial routes, your database config — all the repetitive stuff that takes time but doesn't require deep thinking.
But the moment you need real logic — nuanced error handling, streaming implementations, debugging why your async call hangs — they fall apart. They suggest code that looks right but doesn't work. They miss context. They confidently give you solutions that don't fit your specific situation.
My workflow became: use AI to generate the skeleton, then manually implement the actual functionality. The tools saved me hours on setup but couldn't save me on the hard parts.
One Week Later
Photo by Lucas van Oort on Unsplash
After seven days of learning, I had enough Python and FastAPI knowledge to start building the actual project. Four days later, the backend was functional.
That's eleven days from zero Python to a working backend with a database, API endpoints, and LLM integration. Not bad for someone who'd never touched the language before.
Do I write good Python? Probably not. I write PHP-flavored Python — and I'm okay with that for now. The goal was to learn by building, and I learned more in those eleven days than I would have in a month of tutorials.
Next up: the part that made me choose Python over staying in PHP — streaming AI responses.