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.