Building Your First FastAPI Application: Step-by-Step Tutorial

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. It leverages the latest Python features to provide an intuitive and efficient way to develop APIs. This step-by-step tutorial will guide you through the process of building your first FastAPI application, covering fundamental concepts, usage methods, common practices, and best practices.

Table of Contents

  1. Prerequisites
  2. Installation
  3. Building a Simple FastAPI Application
  4. Adding Path Parameters
  5. Query Parameters
  6. Request Body
  7. Data Validation
  8. Error Handling
  9. Testing Your FastAPI Application
  10. Deployment
  11. Best Practices
  12. Conclusion
  13. References

Prerequisites

  • Basic knowledge of Python programming.
  • Familiarity with RESTful API concepts.

Installation

First, you need to install FastAPI and Uvicorn (a lightning-fast ASGI server). You can use pip to install them:

pip install fastapi uvicorn

Building a Simple FastAPI Application

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"}.

Adding Path Parameters

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

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"}.

Request Body

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}'

Data Validation

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.

Error Handling

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.

Testing Your FastAPI Application

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

Deployment

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

Best Practices

  • Use Type Hints: FastAPI relies on Python type hints for data validation and automatic documentation generation.
  • Organize Your Code: Use modules and packages to keep your codebase organized, especially for larger applications.
  • Write Tests: Testing your API helps catch bugs early and ensures its reliability.
  • Secure Your API: Implement authentication and authorization mechanisms to protect your API endpoints.

Conclusion

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.

References