By Xavier Collantes
Created: 5/30/2025; Updated: 5/30/2025
Set up your environment.
Bash1python3 -m venv env
2source env/bin/activate
3pip install fastapi uvicorn
4
1"""Backend API service that returns a random cat fact."""
2
3from fastapi import FastAPI, Request
4from pydantic import BaseModel
5import random
6import uvicorn
7
8app: FastAPI = FastAPI(title="Cat Facts API", version="1.0.0")
9
10cat_facts: dict[str] = [
11 "Cats sleep 70% of their lives.",
12 "A group of cats is called a clowder.",
13 "Cats have five toes on their front paws, but only four toes on their back paws.",
14 "The world's largest cat measured 48.5 inches long.",
15 "Cats have whiskers on the backs of their front legs as well.",
16 "A house cat can run to the speed of about 30 mph over short distances.",
17 "Cats can make over 100 different sounds.",
18 "The first cat in space was a French cat named Felicette (a.k.a. 'Astrocat') in 1963.",
19]
20
21class CatFact(BaseModel):
22 """Data type for holding fact and ID."""
23
24 cat_fact: str
25 fact_id: int
26
27
28@app.get("/", response_model=CatFact)
29async def get_random_cat_fact():
30 """Get a random cat fact because the internet needs more cats."""
31
32 # Randomly grab a fact on each call.
33 fact: str = random.choice(cat_facts)
34
35 # Fact ID is random number as well.
36 #
37 # Output:
38 # {
39 # "cat_fact": "Cats sleep 70% of their lives.",
40 # "fact_id": 542
41 # }
42 return CatFact(cat_fact=fact, fact_id=random.randint(1, 1000))
43
44
45if __name__ == "__main__":
46 # `host` Running on any local IP address or `localhost` aka `127.0.0.1`.
47 # `port` Some port not being used by another program on your computer.
48 # `reload` Development only. When you make changes to the code, the server
49 # will reload with new changes instead of shutting down this Python
50 # code then starting back up again.
51 uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)
52
http://localhost:8000
.http://localhost:8000/docs
and BAM! You've got interactive API
documentation.1from pydantic import BaseModel
2from fastapi import FastAPI, HTTPException, Query
3
4app = FastAPI()
5
6class UserRequest(BaseModel):
7 name: str
8 email: str
9 age: int
10
11# GET with query parameters.
12@app.get("/users")
13async def get_users(name: str = None, age: int = Query(None, ge=0, le=120)):
14 """Get users with optional filtering."""
15 # Your database magic here.
16 return {"message": f"Finding users named {name}, age {age}"}
17
18# POST with request body.
19@app.post("/users")
20async def create_user(user: UserRequest):
21 """Create a new user."""
22 # Pydantic automatically validates the request body.
23 if user.age < 0:
24 raise HTTPException(status_code=400, detail="Age cannot be negative")
25
26 return {"message": f"Created user {user.name} with email {user.email}"}
27
1from fastapi import FastAPI, File, UploadFile
2import boto3
3from botocore.exceptions import ClientError
4
5app = FastAPI()
6
7@app.post("/upload")
8async def upload_file(file: UploadFile = File(...)):
9 """Upload files to S3 or Supabase (both use boto3)."""
10
11 # Setup your AWS S3 bucket storage.
12 s3_client = boto3.client(
13 "s3",
14 # Get from AWS, Supabase, Firestore, or whatever storage you choose.
15 endpoint_url="https://your-project.supabase.co/storage/v1/s3",
16 aws_access_key_id="your-key",
17 aws_secret_access_key="your-secret",
18 )
19
20 try:
21 s3_client.upload_fileobj(file.file, "your-bucket", file.filename)
22 return {"message": f"Successfully uploaded {file.filename}"}
23
24 except ClientError as e:
25 raise HTTPException(status_code=500, detail=f"Upload failed: {e}")
26
1from pydantic import BaseModel, ConfigDict
2import datetime
3
4def to_camel_case(string: str) -> str:
5 """Convert snake_case to camelCase."""
6 components: str = string.split('_')
7 return components[0] + ''.join(word.capitalize() for word in components[1:])
8
9class UserResponse(BaseModel):
10
11 # Config for model to transform the outputs.
12 model_config = ConfigDict(
13 # Provide function.
14 alias_generator=to_camel_case,
15 # Accept both camelCase and snake_case.
16 populate_by_name=True,
17 )
18
19 # Python uses snake_case.
20 # JavaScript gets camelCase.
21 first_name: str
22 last_name: str
23 birth_date: datetime.date
24
25@app.get("/user", response_model=UserResponse)
26async def get_user():
27 return UserResponse(
28 first_name="Winston",
29 last_name="Wolf",
30 birth_date="1994-10-14"
31 )
32
33# Frontend receives:
34# {
35# "firstName": "Winston",
36# "lastName": "Wolf",
37# "birthDate": "1994-10-14"
38# }
39
1if __name__ == "__main__":
2 uvicorn.run(
3 "main:app",
4 host="0.0.0.0",
5 port=8000,
6 reload=True, # Auto-restart on file changes.
7 )
8
Related by topics: