FastAPI Tutorial: A Quick Guide
FastAPI Tutorial: A Quick Guide
Hey guys! Today we’re diving deep into the awesome world of FastAPI , a modern, fast (hence the name!), web framework for Python. If you’re looking to build APIs quickly and efficiently, you’ve come to the right place. FastAPI has been gaining serious traction in the Python community, and for good reason. It’s built upon standard Python type hints, which makes your code more readable, maintainable, and less prone to errors. Plus, it comes with automatic interactive documentation, which is a lifesaver when you’re developing and testing your APIs. So, grab your favorite beverage, and let’s get started on this FastAPI tutorial journey!
Table of Contents
Getting Started with FastAPI
Alright, first things first, let’s get
FastAPI
up and running. To start building amazing APIs with FastAPI, you’ll need Python installed on your system. If you don’t have it, head over to the official Python website and download the latest version. Once Python is sorted, we need to install FastAPI itself, along with an ASGI server like
uvicorn
. Think of
uvicorn
as the engine that runs your FastAPI application. Open up your terminal or command prompt and type in the following commands:
pip install fastapi
pip install uvicorn[standard]
See? Easy peasy! Now that we have the essential tools, let’s create our very first FastAPI application. Create a new Python file, let’s call it
main.py
, and paste the following code into it:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
This is the absolute basic setup for a FastAPI app. We import
FastAPI
and then create an instance of it called
app
. The
@app.get("/")
part is a decorator. It tells FastAPI that the function
read_root
should handle requests to the root path (
/
) using the
GET
HTTP method. When someone makes a GET request to your API’s root URL, this function will be executed, and it will return a simple JSON response:
{"Hello": "World"}
. Pretty neat, huh?
Now, to run this application, navigate back to your terminal, make sure you’re in the same directory as your
main.py
file, and execute this command:
uvicorn main:app --reload
Let’s break that down:
uvicorn
is our server,
main
refers to the
main.py
file,
app
is the
FastAPI
instance we created inside
main.py
, and
--reload
means the server will automatically restart whenever you make changes to your code. You should see output indicating that
uvicorn
is running, likely on
http://127.0.0.1:8000
. Open your web browser and go to that address. Boom! You should see
{"Hello": "World"}
displayed right there. How cool is that for a
FastAPI tutorial
to get you started?
Building Your First API Endpoint
Now that you’ve got the basic structure running, let’s level up and create our first real API endpoint. APIs often need to handle data, and a common task is retrieving specific items. For example, let’s imagine we’re building a simple API for managing a list of items. We’ll need an endpoint that allows us to get an item by its ID. This is where FastAPI ’s path parameters come into play.
Update your
main.py
file with the following code:
from fastapi import FastAPI
app = FastAPI()
fake_items_db = [
{"item_id": 1, "name": "Foo"},
{"item_id": 2, "name": "Bar"},
{"item_id": 3, "name": "Baz"}
]
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
for item in fake_items_db:
if item.get("item_id") == item_id:
return item
return {"error": "Item not found"}
In this updated code, we’ve introduced a list called
fake_items_db
to simulate a database. The crucial part is the new endpoint:
@app.get("/items/{item_id}")
. Notice the
{item_id}
within the path? This is how you define a path parameter in FastAPI. When a request comes in, say to
/items/2
, FastAPI will capture the
2
and pass it as an argument to our
read_item
function. We’ve also added a type hint:
item_id: int
. This tells FastAPI that
item_id
should be an integer. If a non-integer value is provided (like
/items/abc
), FastAPI will automatically return a validation error, which is super helpful for keeping your API robust. Inside the function, we loop through our fake database to find the item with the matching
item_id
and return it. If no item is found, we return an error message.
Make sure your
uvicorn
server is still running with
--reload
. Now, try accessing
http://127.0.0.1:8000/items/1
in your browser. You should see
{"item_id": 1, "name": "Foo"}
. Try
http://127.0.0.1:8000/items/3
and you should get
{"item_id": 3, "name": "Baz"}
. What if you try an ID that doesn’t exist, like
http://127.0.0.1:8000/items/99
? You’ll see
{"error": "Item not found"}
. This is a fundamental step in our
FastAPI tutorial
, showing how to handle dynamic data retrieval. Pretty slick, right?
Query Parameters in FastAPI
So far, we’ve covered basic GET requests and path parameters. But what about filtering or optional parameters? That’s where
query parameters
shine in FastAPI. Unlike path parameters, which are part of the URL path itself (like
/items/{item_id}
), query parameters come after the
?
in a URL and are key-value pairs separated by
&
(e.g.,
/items/?skip=0&limit=10
).
Let’s enhance our
main.py
to include query parameters for skipping and limiting items. We’ll modify the
read_item
function to accept these optional parameters. Update your
main.py
like this:
from fastapi import FastAPI
from typing import Optional
app = FastAPI()
fake_items_db = [
{"item_id": 1, "name": "Foo"},
{"item_id": 2, "name": "Bar"},
{"item_id": 3, "name": "Baz"},
{"item_id": 4, "name": "Qux"},
{"item_id": 5, "name": "Corge"}
]
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
item = {"item_id": item_id}
if q:
item.update({"q": q})
for db_item in fake_items_db:
if db_item.get("item_id") == item_id:
item.update(db_item)
return item
return {"error": "Item not found"}
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return fake_items_db[skip : skip + limit]
In the
read_item
function, we’ve added
q: Optional[str] = None
.
Optional[str]
means that
q
can either be a string or
None
. By setting the default value to
None
, we make the query parameter
q
optional. If a query parameter
q
is provided in the URL, like
/items/1?q=somequery
, the value
somequery
will be passed to the
q
argument. We then update our returned dictionary with this query value if it exists. This is a powerful feature for adding flexible filtering or metadata to your API responses.
We’ve also added a new endpoint,
@app.get("/items/")
. This endpoint takes two query parameters:
skip
and
limit
, both with default values. If you navigate to
http://127.0.0.1:8000/items/
, you’ll get the first 10 items. If you go to
http://127.0.0.1:8000/items/?skip=2&limit=2
, you’ll get items starting from the third item (index 2) and take 2 items. This demonstrates how
FastAPI
effortlessly handles default values and makes query parameters super easy to implement. It’s a core concept in any good
FastAPI tutorial
!
Request Body and POST Requests
So far, we’ve focused on
GET
requests, which are primarily for retrieving data. But APIs often need to create or update data, which is typically done using
POST
,
PUT
, or
PATCH
requests. These methods often involve sending data in the request
body
.
FastAPI
leverages Python data classes (or Pydantic models, to be precise) to define the structure of this data, making it robust and easy to work with.
Let’s add an endpoint to our
main.py
that accepts a
POST
request to create a new item. First, we need to define the structure of the item we want to create. We’ll use Pydantic models for this. Update your
main.py
as follows:
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
# Define the structure for an Item using Pydantic BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
fake_items_db = [
{"item_id": 1, "name": "Foo", "price": 10.0},
{"item_id": 2, "name": "Bar", "price": 20.0},
{"item_id": 3, "name": "Baz", "price": 30.0}
]
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
item = {"item_id": item_id}
if q:
item.update({"q": q})
for db_item in fake_items_db:
if db_item.get("item_id") == item_id:
item.update(db_item)
return item
return {"error": "Item not found"}
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return fake_items_db[skip : skip + limit]
# Endpoint to create a new item
@app.post("/items/")
def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
response = {"item_id": len(fake_items_db) + 1, **item_dict}
fake_items_db.append(response)
return response
First, we import
BaseModel
from
pydantic
and define our
Item
class inheriting from it. This
Item
model specifies that an incoming item must have a
name
(string), can optionally have a
description
(string), must have a
price
(float), and can optionally have
tax
(float). FastAPI will automatically validate the incoming request body against this model. If the data doesn’t match the structure or types, FastAPI will return a helpful error.
Now, look at the
@app.post("/items/")
endpoint. The function
create_item
takes an argument
item: Item
. This is the magic! By declaring the type hint as
Item
, FastAPI knows to expect a JSON object in the request body that conforms to our
Item
Pydantic model. It automatically parses the JSON, validates it, and passes it to the function as an
Item
object. Inside the function, we convert the Pydantic object to a dictionary (
item.dict()
), calculate
price_with_tax
if tax is provided, assign a new
item_id
, and append it to our
fake_items_db
. We then return the created item.
To test this
POST
endpoint, you can use tools like
curl
, Postman, or even FastAPI’s automatic interactive documentation. Navigate to
http://127.0.0.1:8000/docs
in your browser. You’ll see an interactive API documentation page generated by
FastAPI
! Find the
POST /items/
endpoint, click on it, click