Skip to content

fastapi

install

# install fastapi and uvicorn
pip install fastapi[all]

basic usage

from fastapi import FastAPI

app = FastAPI()

### GET method for /
@app.get("/")
async def root():
    return {"message": "Hello World!"}

# also for POST, PUT, DELETE, ...
@app.post("/")
def rootpost():
    pass

# parameters
@app.get("/items/{id}")
def readitem(id: int):
    return {"item_id": id}

# order matters
# /who/me will invoke getme() since it is defined prior to getuser().
@app.get("/who/me")
def getme():
    pass

@app.get("/who/{user}")
def getuser(user):
    pass

### path parameters (e.g., pass in "/path/to/sth")
# /files//path/to/sth will get /path/to/sth
@app.get("/files/{file_path:path}")
def getfile(file_path):
    pass

### lookup parameters (e.g., ?key=val&key2=val2)
# /items/?index=10 will get index = 10
# /items/ will get index = 0, since we provide a default value, it is not a required parameter.
@app.get("/items/")
def getitem(index: int=0):
    return items[index]

# /items/ will throw an error now, since we provide no default, it is a required parameter.
@app.get("/items/")
def getitem(index: int):
    return items[index]

### post by pydantic
from typing import Optional
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float

@app.post("/post_item/")
def postitem(item: Item): # will decode the post body into a Item instance.
    item_dict = item.dict()
    return item_dict

# also support all the parameters
@app.post("/post_item/{id}")
def postitem(item: Item, id: int, q: int=0):
    item_dict = item.dict()
    item_dict['id'] = id
    item_dict['q'] = q
    return item_dict

### restricted parameters
# the passed in parameter must follow the defined rules.
from fastapi import Query, Path

# path (id, always required) + optional query (key1) + required query (key2)
@app.get("/items/{id}")
def getitem(
    id: int = Path(..., title="item id", gt=0, le=100),
    key1: str = Query("default", min_length=1, max_length=50, regex="^pattern$"),
    key2: str = Query(..., min_length=1, max_length=50, regex="^pattern$")
):
    pass


### error handling
from fastapi import HTTPException

@app.get("/items/{id}")
def getitem(id: int):
    if id not in ITEMS:
        raise HTTPException(status_code=404, detail="item not found")
    return {"item": ITEMS[id]}

debug

the main.py:

import uvicorn
from fastapi import FastAPI

app = FastAPI()

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

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Then run with:

python main.py

deploy

assume the APIs are in main.py, and the backend is called app:

# dev example, will run at localhost:8000, and reload once source file changes.
uvicorn main:app --reload

It will serves:

  • localhost:8000/: the api root.
  • localhost:8000/docs: the api documentation.
  • localhost:8000/redoc: another api documentation, better use with typing.
  • localhost:8000/openapi.json: OpenAPI description.

More options:

uvicorn main:app --host 0.0.0.0 --port 8000

(However, logging with uvicorn seems to be painful.)