FastAPI Tutorial



Why Use FastAPI?

  • Easy to learn
  • Fast development
  • High performance (async by default)

Install and Get Started with FastAPI

  • To install FastAPI, open the terminal and run the following command:
pip install fastapi uvicorn

Uvicorn is the server that will be used ti test and run our FastAPI applications.

  • Create a new directory for the project and create a file named main.py containing the following code:
from fastapi import FastAPI

# Create an app
app = FastAPI()

# define a path for HTTP Get method
@app.get("/")
def root():
    return {"Hello": "World"}
  • To run your server, use uvicron in the terminal:
uvicorn main:app --reload

--reload option automatically refresh anytime you make changes to the file.

  • Click the given URL http://127.0.0.1:8000 , you should be able to see the API route.

GET and POST Routes

In FastAPI, routes are used to define the different URLs that your app should respond to. You can create routes to handle different interactions.

For example, let’s build a to-do list application. We’ll need different routes to add or view the to-do items on the list.

  • In main.py, just after app = FastAPI() create an empty list of items:
items = []
  • Next, create a new endpoint for our app (just after the root endpoint):
@app.post("items")
def create_item(item: str):
    items.append(item)
    return item

Users can access this endpoint by sending an HTTP Post request to this items path, and it’s going to accept item as an input (query parameter).

  • To test the endpoint:
curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8000/items?item=apple'
  • The same way, add an orange item.

  • Create an endpoint to view a specific item of the list, for that add the following code:

@app.get("items/{item_id}")
def get_item(item_id: int) -> str:
    item = items[item_id]
    return item
  • To test the endpoint:
curl -X GET http://127.0.0.1:8000/items/0
  • Now what happens if we try to get an item that doesn’t exist? go back to terminal and try:
curl -X GET http://127.0.0.1:8000/items/7

We get this error: Internal Server Error, so we have to handle the error by raising useful error messages so we can debug it and figure out what went wrong.

Handling HTTP Errors

In FastAPI, it’s easy to raise specific errors to handle whatever situation you are dealing with. For example, to handle the last error sample (Internal Server Error).

There’s a universal set of HTTP response codes that we can use and every body will understand. If an item doesn’t exist, that’s usually a client error. Because the client is looking for a specific item that the server doesn’t know about.

Docs: HTTP response status codes

It’s the 404 Not Found code that has to be used to handle the item not found exception.

  • To do that, import HTTPException from FastAPI:
from fastapi import FastAPI, HTTPException
  • Then modify the get_item() endpoint to use the HTTPException:
@app.get("items/{item_id}")
def get_item(item_id: int) -> str:
    if item_id < len(items):
        return = items[item_id]
    else:
        raise HTTPException(status_code=404, detail=f"Item {item_id} not found")
  • Run the same request again:
curl -X GET http://127.0.0.1:8000/items/7

We get:

{"detail" : "Item 7 not found"}

The error is updated to something more useful!

JSON Request and Path Parameters

Let’s see how we can send information to FastAPI.

  • Create a new endpoint called list_items
# this endpoint uses a query parameter 'limit'
@app.get("/items/")
def list_items(limit: int = 10):
    return items[0:limit]

this function will return by default the first 10 items, or if limit=3, it will return the first 3 items.

  • Test this endpoint (first add at least 10 items to the list):
curl -X GET 'http://127.0.0.1:8000/items?limit=3'

Pydantic models

FastAPI supports Pydantic models which permit to structure data and also provide additional validation. This will make things like testing, documentation and code completion in your IDE easier.

Pydantic is the most widely used data validation library for Python. It lets you structure your data, gives you type-hints and auto-complete in your IDE, and helps to serialize to and from JSON.

  • To get started, import BaseModel from Pydantic:
from pydantic import BaseModel
  • then after app = FastAPI() instruction add the following code that extend BaseModel to create an item class:
class Item(BaseModel):
    text: str = None
    is_done: bool = False
  • Now update the app to use this Item model, so update create_item and get_item to use Item model instead of str:
...
def create_item(item: Item):
...
def get_item(item_id: int) -> Item:
  • Test the create_item endpoint (we have to send data as a JSON payload), so instead of:
curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:8000/items?item=apple'

use:

curl -X POST -H "Content-Type: application/json" -d '{"text":"apple"}' 'http://127.0.0.1:8000/items'

you will get this result:

[{"text":"apple","is_done":False}]
  • We can change the text attribute of the Item class to be required like that:
class Item(BaseModel):
    # without default value
    text: str
    is_done: bool = False

now if we try to add an item without a text value like the following (we put a title field instead) we will get an error, because it’s validating the request model and this’s another advantage of using Pydantic.

curl -X POST -H "Content-Type: application/json" -d '{"title":"apple"}' 'http://127.0.0.1:8000/items'

Response Models

So far, we’ve looked at how to model the request data and the input payload to FastAPI. Let’s look at how we can model the response as well. All we need to do is use the same base model from Pydantic for your response.

  • Let’s update the app where we list items or where we get the item, all we have to do is add a new argument to the decorator called response_model:
...
# Specify the response type will be a list of Item
@app.get("/items", response_model=list[Item])
def list_item(limit: int = 10):
...
# Specify the response type will be an Item model
@app.get("/items/{item_id}", response_model=Item)
def get_item(item_id: int) -> Item:

This is very useful when we want to build a frontend client that interacts with FastAPI because we have a defined response structure.

Interactive Documentation

An other great feature of FastAPI is the interactive documentation. When ever you start a FastAPI server, you get a documentation page that you can interact with and use to test your API.

  • To show the API documentation page, use this url: http://127.0.0.1:8000/docs

This will show the Swagger UI page where you get to see all of your endpoints, which HTTP method they accept and if you click into them you can also look at the type of parameters they take. And you can test them.

  • Also you can use http://127.0.0.1:8000/redoc to get another form of API documentation.

FastAPI vs Flask vs Django

  • FastAPI is:

    • Async by default: it can handle more concurrent requests right out of the box.
    • Easier to use: the way to define routes, response models, validate data and throw HTTP exceptions is as simple as it could be.
  • Flask is more complex

  • Django is a heavyweight framework.


By Wahid Hamdi