http://localhost:8000/docs. But what's actually happening in all those files Cursor generated?Cmd+K (Mac) or Ctrl+K (Windows/Linux)user-api/
βββ main.py # Entry point - starts the API
βββ database.py # Database setup and connection
βββ auth.py # JWT token functions
βββ dependencies.py # Reusable components
βββ models/
β βββ user.py # Database table definition
βββ schemas/
β βββ user.py # API request/response formats
βββ routers/
β βββ users.py # All your endpoints
βββ requirements.txt # Dependencies
βββ .env.example # Environment variables template
βββ README.md # Setup instructions
βββ users.db # SQLite database (appears after first run)main.py) creates the API and connects everything.routers/users.py) handle HTTP requests for each endpoint.schemas/user.py) define what data looks like in requests and responses.models/user.py) define what data looks like in the database.database.py) manages the connection to SQLite.auth.py) handles JWT tokens for authentication.dependencies.py) provides reusable functions like "get current user".main.py. This is where everything starts.app = FastAPI() line. Everything else is configuration.Base.metadata.create_all() creates your database tables automatically. The first time you run the API, it sees you don't have a users table and creates it. This is why you don't need to run separate database setup commands.allow_origins=["*"]). In production, you'd restrict this to specific domains.app.include_router(users.router) connects all your user endpoints. Without this line, the endpoints wouldn't be accessible.engine is your database connection. It knows how to talk to SQLite.SessionLocal creates database sessions. Each time you want to interact with the database, you create a session, do your work, and close it.Base is what your models inherit from. Remember models/user.py? It uses this Base to become a database table.get_db() is a function that gives you a database session and automatically closes it when you're done. This is used throughout your API via FastAPI's dependency injection.users.db) with no separate server to manage. When you deploy to production, you'll change one line to use PostgreSQL instead. The rest of the code stays the same because SQLAlchemy (the ORM) abstracts away the database differences.users table looks like in the database.Column becomes a column in the users table.id uses UUID (Universally Unique Identifier) which looks like "a8f3c2e1-4b7d-4e9a-b3c1-8f2d3e4a5b6c". The default=lambda: str(uuid.uuid4()) generates a new random ID automatically when you create a user.email has unique=True which means the database will reject duplicate emails. It also has index=True for faster lookups.nullable=False means the field is required. nullable=True means it's optional.password column. This stores the hashed password (not the plain text). We'll see how hashing works when we look at the routers.models/user.py with schemas/user.py:UserCreate is what clients send when creating a user. It includes the password because they need to set it. It validates that email is actually an email format (EmailStr).UserResponse is what the API returns. Notice it does not include password. This is a security feature. The password field is write-only - you can send it in, but you never get it back.UserUpdate is for updating users. All fields are Optional because you might only want to update firstName without changing anything else."email": "not-an-email", Pydantic rejects it before your code even runs. If they send "age": 25 but age isn't in your schema, Pydantic ignores it.routers/users.py and you'll see all six endpoints.@router.post("/users") says "this function handles POST requests to /users"response_model=UserResponse tells FastAPI to format the response using UserResponse schema (which excludes password)status_code=201 sets the HTTP status code for successful creationuser: UserCreate means FastAPI will automatically parse the request body as JSON and validate it against the UserCreate schemadb: Session = Depends(get_db) is FastAPI's dependency injection. It calls get_db() from database.py, which gives you a database session. When the function ends, the session automatically closes.User model instance with the dataid, createdAt)UserResponse format)sub is the standard JWT field for "subject").Authorization header for protected endpoints.current_user: User = Depends(get_current_user) - This endpoint requires authentication. The get_current_user dependency extracts the JWT token from the Authorization header, validates it, and loads the user. If the token is invalid or missing, the request fails before this function even runs.if current_user.id != id: - Users can only update their own account. Even with a valid token, you can't modify someone else's data.user_update.dict(exclude_unset=True) - Only update fields that were actually provided. If the client sends {"firstName": "NewName"}, only firstName changes. The exclude_unset=True ignores fields that weren't in the request.create_access_token() creates a JWT token. This token is a cryptographically signed string that contains the user ID and expiration time. The signature uses SECRET_KEY so tokens can't be forged.ACCESS_TOKEN_EXPIRE_HOURS). After that, the user needs to log in again.hash_password() takes a plain password like "SecurePass123" and turns it into something like "$2b$12$KIXxE.j3vFg9QN8hA6Fv0e...". This is a one-way transformation - you can't reverse it to get the original password.verify_password() takes a plain password and a hash, hashes the plain password, and compares the hashes. If they match, the password is correct.HTTPBearer() extracts the Authorization: Bearer <token> header from requests.get_current_user() is a dependency that protected endpoints use. It:Depends(get_current_user) and automatically have access to the authenticated user. The dependency system is incredibly elegant.PUT /users/abc123
Authorization: Bearer eyJhbGc...
{"firstName": "NewName"}main.py) sees this matches the PUT /users/{id} endpoint in routers/users.pyget_db() creates a database sessionget_current_user() validates the JWT token and loads the userUserUpdate schema and validates it{
"id": "abc123",
"email": "user@example.com",
"firstName": "NewName",
...
}Depends() automatically provides database sessions, current user, etc. This keeps code clean and handles setup/cleanup.Cmd+K, and ask. The AI that generated this code is your learning companion.