Environment and first endpoint
- Lesson 4
- 35 min
- Module 2: Build a small FastAPI service
Lesson 4 of 21 · Build and Deploy Your First APIEnvironment and first endpoint
1. Understand the web request
2. Build a small FastAPI service
3. Design a usable contract
4. Document the API with OpenAPI and Swagger UI
5. Explore and test with Postman
6. Test and harden the service
7. Deploy and verify
What you will be able to do
Run your own API on your computer, and prove that it answers. Every later lesson starts from this project and this check.
Before you startWhat to know and to have ready
What you need to know
- How to make and activate a virtual environment, and record the versions, from Isolate dependencies: Worked example: make and use an environment and Isolate dependencies: Record the versions.
- What a package is, from Modules and imports: The new layout.
- How to send a request with curl and read the response, from Inspect a request: Worked example: a request and its response.
What you need on your computer
- Python 3.12 or newer, from Install and verify Python: Step 1: install Python.
- The folder
~/projects, where the Python course keepsticket-cleaner. You made it in Files and terminal: Guided practice: make your project folder. If it is missing, runmkdir ~/projectsfirst. - An internet connection, to install FastAPI (about 25 MB).
Tested with Python 3.14.6 and FastAPI 0.142.2 on macOS.
What FastAPI does
Section titled “What FastAPI does”A web API needs two parts. A server program listens on a port, reads the HTTP text of each request, and writes the HTTP text of each response. A framework turns that request into a call to one of your Python functions, and turns the function’s return value into a response.
FastAPI is a Python framework for APIs. You write normal functions with type hints. FastAPI uses the hints to read the input, check it, convert the output to JSON, and write the documentation. The server program that runs it is Uvicorn. FastAPI installs it for you, and starts it with one command.
An endpoint is one method and one path that the API answers, for example GET /health. Each endpoint has one Python function.
Step 1: make the project
Section titled “Step 1: make the project”The project for this course is ticket-api, next to the ticket-cleaner project from the Python course.
-
Make the project folder, and move into it:
Terminal window mkdir ~/projects/ticket-apicd ~/projects/ticket-api -
Make and activate a virtual environment:
Terminal window python3 -m venv .venvsource .venv/bin/activateTerminal window python -m venv .venv.venv\Scripts\Activate.ps1Terminal window python3 -m venv .venvsource .venv/bin/activateThe prompt starts with
(.venv). -
Install FastAPI with its standard tools. The quotes are needed, because
[ ]has a special meaning in some terminals:Terminal window python -m pip install "fastapi[standard]==0.142.2"[standard]adds the tools that this course uses: Uvicorn, thefastapicommand and httpx. -
Record the dependencies, as in the Python course:
requirements.txt # Needed to run the APIfastapi[standard]==0.142.2Terminal window python -m pip freeze > requirements-lock.txtThe lock file has about 56 lines: FastAPI, Uvicorn, Pydantic and the packages that they need.
Files that stay on your computer
Section titled “Files that stay on your computer”Make the file .gitignore in ticket-api, as in Quality and handoff: A clean project layout:
.venv/__pycache__/.pytest_cache/.env.fastapicloud/Each computer makes the environment and the caches again, and .env can hold secrets, so these files must not leave your computer. Git and the deploy command in Module 7 leave out every file that .gitignore lists. Most of these files do not exist yet: later lessons make them.
Step 2: the first endpoint
Section titled “Step 2: the first endpoint”The code goes in a package, ticket_api, as in Modules and imports. Make the folder ticket_api with two files:
"""A small API that classifies support tickets."""from fastapi import FastAPI
app = FastAPI(title="Ticket Classifier API")
@app.get("/health")def health() -> dict[str, str]: return {"status": "ok"}| Line | Meaning |
|---|---|
app = FastAPI(...) |
The application object. The server gives every request to it. |
@app.get("/health") |
A decorator: it registers the function below it as the endpoint GET /health. |
def health() -> dict[str, str]: |
A normal function. The return type tells FastAPI what the response contains. |
return {"status": "ok"} |
FastAPI turns the dictionary into a JSON body, with status 200. |
A health endpoint answers “the service runs”. It does no real work, so it is fast and almost never fails. Hosting platforms and monitoring tools call it to check that the service is alive. Every API in this course has one.
Step 3: start the server
Section titled “Step 3: start the server”fastapi dev ticket_api/main.py ⚡️ Starting FastAPI in development mode
🐍 Using import string: ticket_api.main:app
🌐 Server started at http://127.0.0.1:8000 Documentation at http://127.0.0.1:8000/docs
Logs:
INFO: Will watch for changes in these directories: ['/Users/amira/projects/ticket-api']INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)INFO: Started reloader process [48081] using WatchFilesINFO: Started server process [48088]INFO: Waiting for application startup.INFO: Application startup complete.fastapi dev starts Uvicorn in development mode. It listens only on your computer (127.0.0.1), on port 8000. It restarts the server each time that you save a Python file. The terminal stays busy while the server runs. That is normal: it is waiting for requests.
Step 4: check it
Section titled “Step 4: check it”Open a second terminal, because the first one is running the server. Then send a request:
curl -i http://127.0.0.1:8000/healthHTTP/1.1 200 OKdate: Tue, 06 Oct 2026 20:39:29 GMTserver: uvicorncontent-length: 15content-type: application/json
{"status":"ok"}In the first terminal, the server writes one log line for each request:
INFO: 127.0.0.1:59501 - "GET /health HTTP/1.1" 200 OKYou can also open http://127.0.0.1:8000/health in your browser. It shows the same JSON.
To stop the server, go to its terminal and press Ctrl+C.
Step 5: a README for the project
Section titled “Step 5: a README for the project”The project now runs, so write down how to run it. A README tells the next person, and you in a month, how to set up and start the project. Make README.md in ticket-api:
# ticket-api
A small web API that classifies support tickets.
## Set up
```shpython3 -m venv .venv # Windows: python -m venv .venvsource .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1python -m pip install -r requirements-lock.txt```
## Run
```shfastapi dev ticket_api/main.py # http://127.0.0.1:8000```Keep it small for now. When a later lesson changes a command, change it in the README too. The sections follow Quality and handoff: The README.
Guided practice: your running API
Section titled “Guided practice: your running API”-
Do steps 1 to 5 on your computer.
-
Request a path that does not exist:
curl -i http://127.0.0.1:8000/nothing.The status is
404 Not Found, and the body is{"detail":"Not Found"}. FastAPI answers every unknown path for you. -
Change the health endpoint to return
{"status": "ok", "service": "ticket-api"}. Change the return type to match. Save the file.In the server’s terminal, you see that it restarts by itself. Send the request again: the new field is there.
-
Stop the server with Ctrl+C, and send the request again. Read the error, and say at which step from Module 1 it failed.
-
Change the endpoint back to
{"status": "ok"}, and start the server again.
Show the answer for step 4
curl answers Failed to connect to 127.0.0.1 port 8000 after 0 ms: Couldn't connect to server. It failed at the connection step: no program listens on port 8000 any more. There is no status code, because no application answered.
Your turn: a second endpoint
Section titled “Your turn: a second endpoint”Add an endpoint GET /version that returns {"version": "0.1.0"}. Check it with curl and in the browser. Then predict: what does curl -i -X POST http://127.0.0.1:8000/version return, and why?
Show the answer
@app.get("/version")def version() -> dict[str, str]: return {"version": "0.1.0"}The POST returns 405 Method Not Allowed with {"detail":"Method Not Allowed"}. The path exists, but only for GET. The response also has the header allow: GET, which tells the client which methods are allowed. You can delete this endpoint now. The next lessons do not use it.
Common mistake
Address already in use
Symptom: fastapi dev stops at once with an error like one of these:
ERROR: [Errno 48] Address already in useERROR: [Errno 98] Address already in useERROR: [WinError 10048] Only one usage of each socket address is normally permittedCause: another program already listens on port 8000. Usually it is the same API, still running in a different terminal or a terminal tab that you forgot. Only one program can listen on a port.
Fix:
- Find the other terminal that runs
fastapi dev, and stop it with Ctrl+C. - If you cannot find it, use a different port for now:
fastapi dev ticket_api/main.py --port 8001, and use8001in your requests. - Closing all terminal windows also stops servers that you started in them.
Check your understanding
You call GET /health, and the API answers 200. What does that prove, and what does it not prove?
Show the answer
It proves that the server runs, listens on the port, and that the application handles requests. It does not prove that the real work works: in later lessons, the classifier could be down while /health still answers 200. Module 7 adds a second check, /ready, for that.
Does your answer have the main points of ours?
Sign in and enroll in the course to save your answers. Every check counts toward the certificate.
Recap
- FastAPI turns HTTP requests into calls to your functions. Uvicorn is the server program that runs it.
- An endpoint is a method and a path, registered with a decorator such as
@app.get("/health"). fastapi dev ticket_api/main.pystarts a development server onhttp://127.0.0.1:8000, which restarts when you save.- Keep the server in one terminal, and send requests from a second one.
- A health endpoint proves that the service runs.
.gitignorekeeps the environment, the caches and secrets on your computer. The README says how to set up and run the project.
Next, you add the real endpoint: it reads a ticket as JSON, checks it, and returns a classification.