Table of Contents
- Introduction
- Prerequisites
- Installing FastAPI
- Creating a FastAPI Application
- Defining Routes
- Handling Query Parameters
- Creating Models
- Handling Request Bodies
- Database Integration with SQLAlchemy
- Authentication and Authorization
- Testing FastAPI Applications
- Deploying FastAPI Applications
- Conclusion
Introduction
FastAPI is a modern, fast (high-performance) web framework for building APIs with Python. It is designed to be easy to use, expressive, and efficient. FastAPI is powered by the Python type hints that provide improved code autocompletion and validation. It is considered as a high-performance alternative to Flask due to its impressive speed and performance optimizations.
In this tutorial, you will learn how to build a web application using FastAPI. By the end of this tutorial, you will be able to create endpoints, handle query parameters and request bodies, integrate with databases, implement authentication and authorization, test your FastAPI application, and deploy it.
Prerequisites
To follow along with this tutorial, you will need:
- Basic knowledge of Python programming language
- Python 3.6 or above installed on your machine
- Familiarity with web development concepts (HTTP, RESTful APIs)
Installing FastAPI
Before we can start building our web application with FastAPI, we need to install the framework. Open your terminal and execute the following command to install FastAPI:
pip install fastapi
FastAPI has some additional dependencies, including Uvicorn, which is an ASGI server implementation. Install Uvicorn by running the following command:
pip install uvicorn
With FastAPI and Uvicorn installed, we are ready to start building our FastAPI application.
Creating a FastAPI Application
To create a FastAPI application, we will first create a new Python file, for example, main.py
. Open your favorite text editor or IDE and create the file.
```python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
``` In the above code, we import the `FastAPI` class from the `fastapi` module and create an instance of it named `app`. We then define a route handler for the root URL (i.e., `/`) using the `@app.get()` decorator. The `read_root()` function is executed when a GET request is made to the root URL.
To run the FastAPI application, open your terminal and navigate to the directory containing the main.py
file. Execute the following command to start the application:
uvicorn main:app --reload
The main:app
argument tells Uvicorn to look for the app
instance in the main.py
file. The --reload
flag enables auto-reloading, which means the server will restart automatically whenever a code change is detected. Leave the server running for now.
Open your browser and visit http://localhost:8000/
. You should see a JSON response with the message “Hello, World”.
Defining Routes
In FastAPI, routes are defined by creating functions and decorating them with the appropriate HTTP method decorator (@app.get()
, @app.post()
, @app.put()
, etc.). This makes it easy to create various endpoints in your application.
Let’s create a new route that returns a list of items. Add the following code to your main.py
file:
```python
from typing import List
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/")
def read_items():
return ["item1", "item2", "item3"]
``` In the above code, we define a new route handler named `read_items()`. This function is executed when a GET request is made to the `/items/` URL. The function returns a list of items as a response.
Restart the server by stopping it with Ctrl + C
and running the uvicorn
command again. Visit http://localhost:8000/items/
in your browser, and you should see the list of items as the response.
Handling Query Parameters
FastAPI allows you to define query parameters in your route handlers to accept additional information from the client. Query parameters are passed in the URL after a question mark (?
) and separated by ampersands (&
).
Let’s modify our /items/
route to accept a limit
query parameter that specifies the maximum number of items to return. Update the code in your main.py
file as follows:
```python
from typing import List
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/")
def read_items(limit: int = 10):
return [f"item{i}" for i in range(1, limit+1)]
``` In the above code, we add a query parameter named `limit` to the `read_items()` function. The default value of `limit` is set to `10`. Inside the function, we use a list comprehension to generate the list of items based on the `limit` parameter.
Restart the server and visit http://localhost:8000/items/?limit=5
in your browser. You should now see only five items in the response.
Creating Models
FastAPI supports automatic generation of interactive API documentation using OpenAPI (formerly Swagger) and JSON Schema. To take full advantage of this feature, we can define models for our data structures.
Let’s create a simple model for an item. Add the following code to your main.py
file:
```python
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
id: int
name: str
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/")
def read_items(limit: int = 10):
items = []
for i in range(1, limit+1):
items.append(Item(id=i, name=f"Item {i}"))
return items
``` In the above code, we import the `BaseModel` class from the `pydantic` module and create a new class named `Item` that extends `BaseModel`. Inside the `Item` class, we define two attributes: `id` and `name`, both with their respective types.
Restart the server and visit http://localhost:8000/docs
in your browser. FastAPI automatically generates an interactive API documentation where you can see the structure of the Item
model and test your /items/
route.
Handling Request Bodies
In addition to query parameters, FastAPI allows you to receive data in the request body. To handle request bodies, we can use the @app.post()
decorator and define a route handler that expects a model as a parameter.
Let’s create a new route that accepts a JSON payload representing an item and adds it to the list of items. Add the following code to your main.py
file:
```python
from typing import List
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
class Item(BaseModel):
id: int
name: str
app = FastAPI()
items = [
Item(id=1, name="Item 1"),
Item(id=2, name="Item 2"),
Item(id=3, name="Item 3"),
]
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/")
def read_items(limit: int = 10):
return items[:limit]
@app.post("/items/")
def add_item(item: Item):
if item.id in [i.id for i in items]:
raise HTTPException(status_code=400, detail="Item already exists")
items.append(item)
return {"message": "Item added successfully"}
``` In the above code, we create a new route handler named `add_item()` decorated with `@app.post()`. This function expects an `item` object of type `Item` to be passed in the request body. We validate if the item with the same ID already exists and return an error if so. Otherwise, we add the item to the `items` list and return a success message.
Restart the server and use an API testing tool like Postman or cURL to send a POST request to http://localhost:8000/items/
with a JSON payload containing an item.
Database Integration with SQLAlchemy
FastAPI can be easily integrated with databases using libraries like SQLAlchemy. SQLAlchemy is a powerful Object-Relational Mapping (ORM) library for Python that provides a high-level, SQL expression-based interface for database operations.
To integrate SQLAlchemy with FastAPI, we first need to install the necessary dependencies. Execute the following command in your terminal:
pip install sqlalchemy databases[postgresql]
In the above command, we install SQLAlchemy and the PostgreSQL driver for databases. You can replace postgresql
with the database driver of your choice if you’re using a different database.
Let’s create a model and connect it to a PostgreSQL database. Assuming you have a PostgreSQL database running locally, add the following code to your main.py
file:
```python
from typing import List
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from databases import Database
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "postgresql://localhost/database_name"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
class ItemCreate(BaseModel):
name: str
app = FastAPI()
database = Database(SQLALCHEMY_DATABASE_URL)
@app.on_event("startup")
async def startup():
await database.connect()
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
@app.get("/items/")
async def read_items():
query = Item.__table__.select()
return await database.fetch_all(query)
@app.post("/items/")
async def add_item(item: ItemCreate):
query = Item.__table__.insert().values(name=item.name)
try:
await database.execute(query)
return {"message": "Item added successfully"}
except:
raise HTTPException(status_code=500, detail="Internal server error")
``` In the above code, we import the necessary modules and create a database URL string that specifies the database driver and location. We then create a SQLAlchemy engine and session maker, which will be used for database operations.
The Item
model is defined as a subclass of Base
and mapped to the items
table. We also create a ItemCreate
model that represents the data needed to create a new item.
To connect to the database, we define two startup and shutdown event handlers using the @app.on_event()
decorator. These event handlers ensure that the database connection is established and closed when the application starts and stops.
The read_items()
and add_item()
route handlers are updated to use the database connection. We perform database queries using SQLAlchemy’s SQL expressions and execute them using the database.execute()
function.
Restart the server and test your /items/
POST and GET routes to interact with the PostgreSQL database.
Authentication and Authorization
FastAPI provides various authentication and authorization options to secure your APIs. One popular option is to use JSON Web Tokens (JWT) for authentication.
To implement JWT authentication with FastAPI, we need to install the required dependencies. Execute the following command in your terminal:
pip install python-jose[cryptography] passlib[bcrypt]
In the above command, we install python-jose
for working with JWT and passlib
with bcrypt
for hashing passwords.
Implementing a complete JWT authentication system is beyond the scope of this tutorial. However, we can outline the basic steps involved:
- Create a user model to represent the user in the database.
- Hash and verify user passwords using
passlib
andbcrypt
. - Generate JWT tokens upon successful authentication.
- Protect your routes with an authentication middleware that validates and decodes JWT tokens.
The exact implementation may vary depending on your requirements and the libraries used.
Testing FastAPI Applications
FastAPI applications can be tested using the built-in TestClient
class, which allows you to simulate HTTP requests to your application.
To write tests for your FastAPI application, you will need to install the httpx
library, which is a dependency of FastAPI. Execute the following command in your terminal:
pip install httpx
Let’s write a simple test for our /items/
route that ensures it returns the correct response. Create a new file named test_main.py
in the same directory as your main.py
file and add the following code:
```python
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_items():
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"},
{"id": 3, "name": "Item 3"},
]
``` In the above code, we import the `TestClient` class from `fastapi.testclient` and create an instance of it by passing our `app` instance. We then define a test function named `test_read_items()` that sends a GET request to `/items/` and asserts that the response status code is 200 and the JSON response matches the expected content.
To run the test, execute the following command in your terminal:
python -m pytest test_main.py
If everything is set up correctly, you should see the test result indicating that the test passed.
Deploying FastAPI Applications
FastAPI applications can be deployed using various services and platforms. Some popular deployment options include:
- Cloud platforms like AWS, GCP, or Azure
- Containerization using Docker and Kubernetes
- Serverless platforms like AWS Lambda or Google Cloud Functions
The exact deployment process depends on your chosen deployment option. You may need to configure your server, install dependencies, and expose your FastAPI application to an accessible URL.
Please refer to the official FastAPI documentation and the documentation of your deployment platform for specific instructions on how to deploy your FastAPI application.
Conclusion
In this tutorial, you learned how to build a web application using FastAPI, a high-performance alternative to Flask. You learned about the basics of FastAPI, including how to define routes, handle query parameters and request bodies, create models, integrate with databases using SQLAlchemy, and secure your application with authentication and authorization.
You also learned how to test your FastAPI applications using the built-in TestClient
class and explored various deployment options for FastAPI applications.
By now, you should have a good understanding of FastAPI and be able to develop high-performance web applications with ease. FastAPI’s combination of fast performance, type checking, and automatic documentation generation makes it a powerful choice for Python web development.
Remember to refer to the official FastAPI documentation for more detailed information on advanced features and capabilities.
Frequently Asked Questions
Q: Can I use FastAPI with other databases like MySQL or SQLite?
A: Yes, you can use FastAPI with other databases supported by SQLAlchemy. Simply replace the SQLALCHEMY_DATABASE_URL
with the appropriate URL for your database.
Q: How can I add authentication to my FastAPI application?
A: FastAPI provides various options for authentication, including JWT, OAuth2, and more. You can refer to the FastAPI documentation or search for tutorials