First, you need to install FastAPI and Uvicorn (a lightning-fast ASGI server). You can use pip
to install them:
pip install fastapi uvicorn
Let’s start by creating a simple “Hello, World!” FastAPI application.
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
To run the application, use the following command in your terminal:
uvicorn main:app --reload
Now, open your browser and go to http://127.0.0.1:8000
. You should see a JSON response {"Hello": "World"}
.
Path parameters are variables in the path of the URL. For example, let’s create an API to get an item by its ID.
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
Here, item_id
is a path parameter of type int
. If you access http://127.0.0.1:8000/items/42
, you’ll get {"item_id": 42}
.
Query parameters are used to pass additional information in the URL after the ?
symbol. Let’s modify our previous example to accept an optional q
query parameter.
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
if q:
return {"item_id": item_id, "q": q}
return {"item_id": item_id}
Now, if you access http://127.0.0.1:8000/items/42?q=test
, you’ll get {"item_id": 42, "q": "test"}
.
To receive data in the request body, you can use Pydantic models. Let’s create an API to create an item.
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = None
@app.post("/items/")
def create_item(item: Item):
return item
You can use tools like curl
or Postman to send a POST request with a JSON body. For example:
curl -X POST "http://127.0.0.1:8000/items/" -H "Content-Type: application/json" -d '{"name": "Foo", "price": 42.0}'
FastAPI uses Pydantic for data validation. If the input data doesn’t match the expected type or format, it will automatically return a 422 Unprocessable Entity response. For example, if you try to send an invalid item_id
(non-integer) in the previous path parameter example, you’ll get an error response.
FastAPI provides built-in error handling. However, you can also define custom error handlers. For example, let’s handle a specific exception.
# main.py
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
if item_id < 0:
raise HTTPException(status_code=400, detail="Item ID cannot be negative")
return {"item_id": item_id}
Now, if you access http://127.0.0.1:8000/items/-1
, you’ll get a 400 Bad Request response with the custom error message.
You can use the TestClient
from fastapi.testclient
to test your application.
# test_main.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_item():
response = client.get("/items/42")
assert response.status_code == 200
assert response.json() == {"item_id": 42}
You can run the tests using a test runner like pytest
:
pytest test_main.py
There are several ways to deploy a FastAPI application. One common approach is to use a cloud provider like Heroku or Google Cloud Platform. You can also use Docker to containerize your application. Here’s a simple example of a Dockerfile:
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
Then, you can build and run the Docker image:
docker build -t my-fastapi-app .
docker run -p 80:80 my-fastapi-app
In this tutorial, we’ve covered the essential steps to build your first FastAPI application. We’ve explored path parameters, query parameters, request bodies, data validation, error handling, testing, and deployment. FastAPI’s simplicity and performance make it a great choice for building modern APIs with Python. By following the best practices, you can develop robust and scalable applications.