Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions fastapi-python-web-apis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# A Close Look at a FastAPI Example Application

This repository contains code snippets discussed in the associated tutorial on [A Close Look at a FastAPI Example Application](https://realpython.com/fastapi-python-web-apis/).

## Installation

The recommended way to install FastAPI is with the `[standard]` extra dependencies. This ensures you get all the tools you need for developing an API without having to hunt down additional packages later:

```console
$ python -m pip install "fastapi[standard]"
```

The quotes around `"fastapi[standard]"` ensure the command works correctly across different [terminals](https://realpython.com/terminal-commands/) and operating systems. With the command above you install several useful packages, including the [FastAPI CLI](https://fastapi.tiangolo.com/fastapi-cli/) and [uvicorn](https://www.uvicorn.org/), an ASGI server for running your application.

You can also use the `requirements.txt` file in this folder and run `python -m pip install -r requirements.txt` to install the standard dependencies of FastAPI.
174 changes: 174 additions & 0 deletions fastapi-python-web-apis/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import random
from typing import Annotated

from pydantic import BaseModel, Field

from fastapi import FastAPI, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware

tags_metadata = [
{
"name": "Random Playground",
"description": "Generate random numbers",
},
{
"name": "Random Items Management",
"description": "Create, shuffle, read, update and delete items",
},
]

app = FastAPI(
title="Randomizer API",
description="Shuffle lists, pick random items, generate random numbers.",
version="1.0.0",
openapi_tags=tags_metadata,
)

app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "https://example.com"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["*"],
)

items_db = []


class Item(BaseModel):
name: str = Field(
min_length=1, max_length=100, description="The item name"
)


class ItemResponse(BaseModel):
message: str
item: str


class ItemListResponse(BaseModel):
original_order: list[str]
randomized_order: list[str]
count: int


class ItemUpdateResponse(BaseModel):
message: str
old_item: str
new_item: str


class ItemDeleteResponse(BaseModel):
message: str
deleted_item: str
remaining_items_count: int


@app.get("/", tags=["Random Playground"])
async def home():
return {"message": "Welcome to the Randomizer API"}


@app.get("/random/{max_value}")
async def get_random_number(max_value: int, tags=["Random Playground"]):
return {"max": max_value, "random_number": random.randint(1, max_value)}


@app.get("/random-between", tags=["Random Playground"])
def get_random_number_between(
min_value: Annotated[
int | None,
Query(
title="Minimum Value",
description="The minimum random number",
ge=1,
le=1000,
),
] = 1,
max_value: Annotated[
int | None,
Query(
title="Maximum Value",
description="The maximum random number",
ge=1,
le=1000,
),
] = 99,
):
if min_value > max_value:
raise HTTPException(
status_code=400, detail="min_value can't be greater than max_value"
)

return {
"min": min_value,
"max": max_value,
"random_number": random.randint(min_value, max_value),
}


@app.post(
"/items", response_model=ItemResponse, tags=["Random Items Management"]
)
def add_item(item: Item):
if item.name in items_db:
raise HTTPException(status_code=400, detail="Item already exists")

items_db.append(item.name)
return ItemResponse(message="Item added successfully", item=item.name)


@app.get(
"/items", response_model=ItemListResponse, tags=["Random Items Management"]
)
def get_randomized_items():
randomized = items_db.copy()
random.shuffle(randomized)

return ItemListResponse(
original_order=items_db,
randomized_order=randomized,
count=len(items_db),
)


@app.put(
"/items/{update_item_name}",
response_model=ItemUpdateResponse,
tags=["Random Items Management"],
)
def update_item(update_item_name: str, item: Item):
if update_item_name not in items_db:
raise HTTPException(status_code=404, detail="Item not found")

if item.name in items_db:
raise HTTPException(
status_code=409, detail="An item with that name already exists"
)

index = items_db.index(update_item_name)
items_db[index] = item.name

return ItemUpdateResponse(
message="Item updated successfully",
old_item=update_item_name,
new_item=item.name,
)


@app.delete(
"/items/{item}",
response_model=ItemDeleteResponse,
tags=["Random Items Management"],
)
def delete_item(item: str):
if item not in items_db:
raise HTTPException(status_code=404, detail="Item not found")

items_db.remove(item)

return ItemDeleteResponse(
message="Item deleted successfully",
deleted_item=item,
remaining_items_count=len(items_db),
)
39 changes: 39 additions & 0 deletions fastapi-python-web-apis/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
annotated-types==0.7.0
anyio==4.10.0
certifi==2025.8.3
click==8.2.1
dnspython==2.7.0
email_validator==2.2.0
fastapi==0.116.1
fastapi-cli==0.0.8
fastapi-cloud-cli==0.1.5
h11==0.16.0
httpcore==1.0.9
httptools==0.6.4
httpx==0.28.1
idna==3.10
Jinja2==3.1.6
markdown-it-py==4.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
pydantic==2.11.7
pydantic_core==2.33.2
Pygments==2.19.2
python-dotenv==1.1.1
python-multipart==0.0.20
PyYAML==6.0.2
rich==14.1.0
rich-toolkit==0.15.0
rignore==0.6.4
sentry-sdk==2.34.1
shellingham==1.5.4
sniffio==1.3.1
starlette==0.47.2
typer==0.16.0
typing-inspection==0.4.1
typing_extensions==4.14.1
urllib3==2.5.0
uvicorn==0.35.0
uvloop==0.21.0
watchfiles==1.1.0
websockets==15.0.1