1 - First Steps#

First, we define main.py:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

Then, we can launch the FastAPI server with the command below:

# fastapi dev main.py

When you run a FastAPI server locally, it will be at http://127.0.0.1:8000 by default.

Additionally, Swagger docs will be available at http://127.0.0.1:8000/docs and ReDoc docs will be available at http://127.0.0.1:8000/redoc.

Path Parameters#

You can declare path parameters or variables with the same syntax used by Python f-strings:

@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}
import requests

url = 'http://127.0.0.1:8000'
requests.get(url + '/items/pikachu').json()
{'detail': [{'type': 'int_parsing',
   'loc': ['path', 'item_id'],
   'msg': 'Input should be a valid integer, unable to parse string as an integer',
   'input': 'pikachu'}]}

You can also declare the type of the type of a path parameter in a function:

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}
requests.get(url + '/items/1790').json()
{'item_id': 1790}
requests.get(url + '/items/pikachu')
<Response [422]>

If a path could be resolved by two different path operations (e.g. /users/michael and /users/{username}), then whichever one appears first in the code is what will be used.

Predefined Values in Path Parameters#

Python’s Enum class can be used to allow us to have a path parameter with predefined values. These possible values will appear in the Swagger docs.

from enum import Enum

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}
requests.get(url + '/models/lenet').json()
{'model_name': 'lenet', 'message': 'LeCNN all the images'}

Path Parameters Containing Paths#

@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}
requests.get(url + '/files//michael/hello.txt').json()
{'file_path': '/michael/hello.txt'}

Query Parameters#

When you declare other function parameters that are not path parameters, they are automatically interpreted as query parameters.

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]

@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]
requests.get(url + '/items?skip=1&limit=1').json()
[{'item_name': 'Bar'}]

We can also use None to declare optional parameters:

@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None):
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}
requests.get(url + '/items/pikachu?q=blastoise').json()
{'item_id': 'pikachu', 'q': 'blastoise'}

Type Conversion#

You can use 1, True, true, on, or yes for True, and 0, False, false, off, or no for False.

@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None, short: bool = False):
    item = {"item_id": item_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item
requests.get(url + '/items/pikachu?q=blastoise&short=False').json()
{'item_id': 'pikachu',
 'q': 'blastoise',
 'description': 'This is an amazing item that has a long description'}
params = {
    'q': 'blastoise',
    'short': False
}
requests.get(url + '/items/pikachu', params=params).json()
{'item_id': 'pikachu',
 'q': 'blastoise',
 'description': 'This is an amazing item that has a long description'}

To ensure that a parameter is required, don’t provide a default value.