# FastAPI from Scratch: Installation, app = FastAPI(), a First Route and Running the Server<no value>

## What will we learn?

This lesson is a **full setup, from scratch**, of a real server:

1. **A virtual environment** (venv): where libraries are installed.
2. **Installing FastAPI** with `pip`.
3. **`main.py`**: importing, creating `app`, and a first **Route**.
4. **Running** it with `uvicorn`.
5. **Testing**: the browser, curl, and the automatic documentation page `/docs`.

## Why do we need this?

In the networking topic we saw what a "manual" server involves: `bind`, `listen`, `accept`, and decoding text. That is a lot of work, and it is easy to crash on bad input. **FastAPI** does all of this for us: it receives the request, decodes HTTP, finds the right function, converts the response to JSON, and checks types. We write **only the logic**.

FastAPI is one of the most common libraries for a Backend in Python, especially for APIs and in the worlds of Data and AI.

## Explanation from the basics

### What is FastAPI?

**FastAPI** is a **Framework** for building Web APIs in Python. A Framework = a library that dictates a **structure**: "you write functions, and I call them when a matching request arrives".

**Uvicorn** is **the HTTP server** itself: the program that listens on a port (the networking topic: `listen`), receives connections, and passes every request to FastAPI. FastAPI = **what** to answer. Uvicorn = **the reception** at the entrance.

```text
Browser ──HTTP──► Uvicorn (listens on port 8000) ──► FastAPI (finds the right function) ──► your function
        ◄──JSON── Uvicorn ◄── FastAPI (converts dict to JSON) ◄──────────────────────── return {...}
```

### An external library and pip

Until now we used only modules **that come with Python** (`os`, `json`, `logging`). FastAPI is an **external library** (a Third-party Package), so it has to be installed.

**pip** is Python's package manager: it downloads libraries from **PyPI** (Python's public library repository) and installs them.

### A virtual environment (venv) — and why it is needed

If you install libraries "globally" (for the whole computer), one project needs FastAPI version 0.100, and another project needs 0.142, and there is a conflict. A **Virtual Environment** (venv) = **a private folder for the project**, with its own copy of Python and of its libraries. Every project with its own libraries, without conflicts.

{{< box "analogy" "Analogy: a toolbox for every project" >}}
A handyman who works on three houses does not keep all the tools in one pile at home. Every work site has **a toolbox of its own**, with exactly what the site needs. venv = the project's toolbox. And "activating" it (activate) = "I am working now with **this** box".
{{< /box >}}

### Decorator — `@app.get("/")`

A line that starts with `@` above a `def` is a **Decorator** (we saw `@property` in the OOP topic). In FastAPI, `@app.get("/")` says: **"register the function below as the handler of `GET` requests to the path `/`"**.

Remember the calculator with a dict of functions (`OPERATIONS = {"+": add, ...}`)? FastAPI builds exactly such a table: **(Method, Path) → function**. Every `@app.get(...)` adds a row to the table. When a request arrives, FastAPI looks it up in the table and calls the function. (This is Functions as Objects in action!)

**Route** = the link between an Endpoint (Method + Path) and the function that handles it.

## Syntax

### Step 1 — a folder and a virtual environment

```powershell
mkdir ~\dev\kodkod6\week-4\hello-api
cd ~\dev\kodkod6\week-4\hello-api
python -m venv .venv
```

### Step 2 — activating the environment

**Windows (PowerShell):**

```powershell
.venv\Scripts\Activate.ps1
```

**Mac / Linux:**

```bash
source .venv/bin/activate
```

The Prompt changes and starts with `(.venv)`. **From now on `python` and `pip` belong to the project.**

### Step 3 — installing

```powershell
pip install "fastapi[standard]"
```

`[standard]` installs FastAPI **together with** Uvicorn and a few more useful tools. A check:

```powershell
pip list
```

### Step 4 — `main.py`

```python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def home():
    return {"message": "Hello from my first server!"}
```

### Step 5 — running

```powershell
uvicorn main:app --reload
```

### Step 6 — testing

- The browser: `http://127.0.0.1:8000/`
- The documentation: `http://127.0.0.1:8000/docs`
- Stopping: `Ctrl + C`

## First code example

After steps 1–5, the Terminal shows:

```text
INFO:     Will watch for changes in these directories: ['C:\\Users\\dana\\dev\\kodkod6\\week-4\\hello-api']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [43864] using StatReload
INFO:     Started server process [29224]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```

In the browser, `http://127.0.0.1:8000/`:

```json
{"message":"Hello from my first server!"}
```

And in the Terminal a line about the request is added:

```text
INFO:     127.0.0.1:52311 - "GET / HTTP/1.1" 200 OK
```

## Breaking down the code line by line

**`main.py`:**

| Line | Explanation |
|---|---|
| `from fastapi import FastAPI` | Imports the **Class** named `FastAPI` from the library (the modules lesson: `from ... import`). |
| `app = FastAPI()` | Creates an **object** from the Class (the OOP topic!). `app` is **the application**: it holds the table of Routes, and Uvicorn will talk to it. |
| `@app.get("/")` | A Decorator: "register `home` as the handler of `GET /`". `get` is a **method** of the object `app`. |
| `def home():` | A regular function. The name is free. FastAPI recognizes it by the Decorator, not by its name. |
| `return {"message": "..."}` | You return a **dict**, and FastAPI converts it to **JSON** automatically (Serialization, the JSON lesson) and returns Status 200. |

**The command `uvicorn main:app --reload`:**

| Part | Explanation |
|---|---|
| `uvicorn` | Starting the HTTP server. |
| `main` | **The module**: the file `main.py` (without `.py`). |
| `:app` | **The object** inside the module: the variable `app`. "Run the application called `app`, which is in `main`". |
| `--reload` | **Development mode**: when you save a change in the code, the server restarts itself automatically. **Only for development**, not on a real server. |

**The output lines:**

| Line | Meaning (and the connection to the networking topic) |
|---|---|
| `Will watch for changes...` | The `--reload` mode: watching the files in the folder. |
| `Uvicorn running on http://127.0.0.1:8000` | The server **listens** (`listen`) on **localhost**, **port 8000**. |
| `Started reloader process [43864]` | A "watcher" process that detects changes. A **PID**. |
| `Started server process [29224]` | **The process** that really handles the requests. Another PID. |
| `"GET / HTTP/1.1" 200 OK` | A **log** of every request: the Method, the Path, the version and the Status Code. |

## Another example

**More Routes, and `/docs`.** Update `main.py` (with `--reload`, the server updates by itself the moment you save):

```python
from fastapi import FastAPI

app = FastAPI(title="Kodkod Hello API")

COURSE = {"name": "Kodkod 6", "weeks": 5, "topics": ["OS", "Python", "OOP", "Backend", "DB"]}

@app.get("/")
def home():
    return {"message": "Hello from my first server!"}

@app.get("/course")
def course_info():
    return COURSE

@app.get("/course/topics")
def course_topics():
    return COURSE["topics"]

@app.get("/health")
def health():
    return {"status": "ok"}
```

**Tests with curl** (in **another** Terminal, because the first one is busy with the server):

```powershell
curl.exe http://127.0.0.1:8000/course
curl.exe http://127.0.0.1:8000/course/topics
curl.exe -i http://127.0.0.1:8000/nothing
```

**Output:**

```text
{"name":"Kodkod 6","weeks":5,"topics":["OS","Python","OOP","Backend","DB"]}
["OS","Python","OOP","Backend","DB"]
HTTP/1.1 404 Not Found
date: Tue, 06 Oct 2026 14:30:00 GMT
server: uvicorn
content-length: 22
content-type: application/json

{"detail":"Not Found"}
```

**Breakdown:**

- `FastAPI(title="Kodkod Hello API")` — a name for the application, which will appear in the documentation page.
- **You can return anything JSON knows how to represent**: a dict (`/course`), a **list** (`/course/topics`), a string or a number.
- **A path that was not defined** (`/nothing`): FastAPI returns a **404** by itself, with an error JSON. We did not write a single line for it.
- `/health` — an Endpoint common on real servers: monitoring systems check it every few seconds, to know that the server is alive.

### `/docs` — the automatic documentation

Open `http://127.0.0.1:8000/docs`. FastAPI **built by itself** an interactive documentation page (called **Swagger UI**):

- A list of **all the Endpoints**, with the Method and the Path.
- Clicking an Endpoint → **Try it out** → **Execute**: sends a real request and shows the response.
- The documentation updates automatically with every new Route.

In the students API topic we will use it as the server's **main testing tool**.

## Common mistake

**Mistake 1: installing without activating the venv**, or opening a new Terminal and forgetting to activate it.

```text
uvicorn : The term 'uvicorn' is not recognized ...
```

Or:

```text
ModuleNotFoundError: No module named 'fastapi'
```

**A check:** does the Prompt start with `(.venv)`? If not, `.venv\Scripts\Activate.ps1`. **In every new Terminal, activate it again.** (An alternative that always works: `python -m uvicorn main:app --reload`.)

**Mistake 2: on Windows, activation is blocked.**

```text
.venv\Scripts\Activate.ps1 cannot be loaded because running scripts is disabled on this system.
```

PowerShell blocks running scripts by default. Open PowerShell and run **once**:

```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```

(This allows local scripts for your user only. Remember permissions from the operating system topic!)

**Mistake 3: `main:app` does not match the code.**

```text
ERROR:    Error loading ASGI app. Attribute "app" not found in module "main".
```

The file is not named `main.py`, or the variable is not named `app` (for example `application = FastAPI()`). The format is always `<file>:<variable>`. And you run it **from the folder where the file is** (the Current Working Directory, remember the operating system topic!).

**Mistake 4: a port that is taken.**

```text
ERROR:    [WinError 10048] error while attempting to bind on address ('127.0.0.1', 8000): only one usage of each socket address (protocol/network address/port) is normally permitted
```

Another server (or a previous copy of the same server) is already listening on 8000 (remember ports from the networking topic!). Stop it with `Ctrl + C` in its Terminal, or run on another port: `uvicorn main:app --reload --port 8001`.

**Mistake 5: putting `.venv` into Git.** The folder is huge and contains thousands of files, which depend on your computer. Add to `.gitignore`:

```text
.venv/
__pycache__/
```

And instead, save a **list** of the libraries: `pip freeze > requirements.txt`. Whoever downloads the project runs `pip install -r requirements.txt`.

<!-- exercises:start — generated by scripts/intro6/sync_site_exercises.py; edit scripts/intro6/exercises/ -->
## Practice

The exercises use only what was taught in this lesson and the lessons before it. Try on your own first, and only then open the solution.

### Exercise 1: Setting up a project

Write the sequence of commands that sets up a project `hello-api`: a folder, a virtual environment, activating it (Windows), and installing FastAPI. What is the role of the virtual environment?

{{< solution >}}
```powershell
mkdir hello-api
cd hello-api
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install "fastapi[standard]"
pip list
```

(On Mac: `source .venv/bin/activate`.)

**A virtual environment (venv)** isolates the project's packages: every project with its own versions, without conflicting with other projects or with the computer's Python. The `.venv` folder does not go into Git.
{{< /solution >}}

### Exercise 2: A first Route

Write a `main.py` with a FastAPI application and a Route for `/` that returns `{"message": "Hello from my first server!"}`. How do you run it, and which address do you browse to?

{{< solution >}}
```python
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def home():
    return {"message": "Hello from my first server!"}
```

Run it:

```powershell
uvicorn main:app --reload
```

And browse to `http://127.0.0.1:8000`. `main:app` = the file `main.py`, the variable `app`. `--reload` restarts the server after every save.
{{< /solution >}}

### Exercise 3: From a request to a function

Put in order the path of a request, from the browser to our function and back:

- (a) FastAPI converts the dict to JSON
- (b) The browser sends `GET /`
- (c) The function `home()` returns a dict
- (d) Uvicorn receives the request on port 8000
- (e) FastAPI finds the function that matches `GET /`

{{< solution >}}
The order: **(b), (d), (e), (c), (a)**

1. The browser sends `GET /`.
2. **Uvicorn** — the server itself — receives the request on port 8000.
3. **FastAPI** finds the Route that matches the Method and the path.
4. Our function returns a regular **dict**.
5. FastAPI converts it to **JSON** and returns a response with 200.
{{< /solution >}}

### Exercise 4: Quotes API

Write a quotes API with a list of quotes (dictionaries with `text` and `author`), and two Routes:

- `GET /quotes` — all the quotes;
- `GET /quotes/count` — `{"count": <number>}`.

Give the application the title `"Quotes API"`.

{{< solution >}}
```python
from fastapi import FastAPI

app = FastAPI(title="Quotes API")

QUOTES = [
    {"text": "Simple is better than complex.", "author": "The Zen of Python"},
    {"text": "Readability counts.", "author": "The Zen of Python"},
    {"text": "Talk is cheap. Show me the code.", "author": "Linus Torvalds"},
]


@app.get("/quotes")
def all_quotes():
    return QUOTES


@app.get("/quotes/count")
def count_quotes():
    return {"count": len(QUOTES)}
```

`GET /quotes/count` returns `{"count": 3}`. FastAPI converts a list to JSON too. The title appears in the documentation page at `/docs`.
{{< /solution >}}

### Exercise 5: Swagger UI

1. What is at the address `http://127.0.0.1:8000/docs`?
2. How do you use it to test a Route?

{{< solution >}}
1. **Swagger UI** — a documentation page that FastAPI builds **automatically** from the code: all the Routes, the Method of each one, the parameters and the responses.
2. Open a Route, click **Try it out**, fill in parameters if there are any, and click **Execute**. You see the request that was sent, the Status Code and the response body — without writing a Client.
{{< /solution >}}

<!-- exercises:end -->

## Summary

- **FastAPI** = a Framework in which you define Routes. **Uvicorn** = the HTTP server that listens on the port and passes requests to FastAPI.
- **venv**: `python -m venv .venv`, activating it (`Activate.ps1` / `source .venv/bin/activate`), and then `pip install "fastapi[standard]"`. In every new Terminal, activate it again.
- `app = FastAPI()` = the application object. **`@app.get("/path")`** registers a function as the handler of `GET /path`.
- Return a dict or a list, and FastAPI converts it to JSON with 200. A path that does not exist gets a 404 automatically.
- Running: **`uvicorn main:app --reload`** (`file:variable`), from the file's folder. Stopping: `Ctrl + C`.
- **`/docs`** = interactive, automatic documentation and testing.
- `.venv/` in `.gitignore`. `requirements.txt` in Git.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

## Official documentation

- [FastAPI — Virtual Environments](https://fastapi.tiangolo.com/virtual-environments/)
- [FastAPI — First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/)
- [FastAPI — Interactive API docs](https://fastapi.tiangolo.com/tutorial/first-steps/#interactive-api-docs)

<!-- docs:end -->
