FastAPI is a high-performance Python web framework for building APIs quickly and efficiently.
When combined with Pydantic for data validation and Neon's serverless Postgres for data storage, you can create a powerful and efficient API with minimal effort.
In this guide, we'll walk through the process of building an API for managing a tech conference system, focusing on best practices and performance optimizations.
Prerequisites
Before we begin, make sure you have the following:
- Python 3.9 or later installed on your system
- pip for managing Python packages
- A Neon account for serverless Postgres
Setting up the Project
Let's start by creating a new project directory and setting up a virtual environment:
-
Create a new directory and navigate to it:
-
Create a virtual environment:
Creating a virtual environment isolates your project dependencies from other Python installations on your system.
-
Activate the virtual environment:
- On Windows:
- On macOS and Linux:
You should see
(venv)
in your terminal prompt, indicating that the virtual environment is active.
Now, let's install the necessary packages for our project using pip
:
This command installs:
- FastAPI: Our web framework
- Uvicorn: An ASGI server to run our FastAPI application
- SQLAlchemy: An ORM for database interactions
- psycopg2-binary: PostgreSQL adapter for Python
- Pydantic: For data validation and settings management
- python-dotenv: To load environment variables from a .env file
With the dependencies installed, we can start building our API.
You can also create a requirements.txt
file to manage your dependencies by running:
This will create a requirements.txt
file with all the installed packages in your virtual environment and their versions. This is useful for sharing your project with others or deploying it to a server.
Connecting to Neon Postgres
First, let's set up our database connection. Create a .env
file in your project root:
Replace the placeholders with your actual Neon database credentials.
Now, create a database.py
file to manage the database connection:
This script does the following:
- Loads the environment variables from
.env
usingload_dotenv
- Creates a SQLAlchemy engine using the database URL from the environment variables
- Creates a SessionLocal class for database sessions
- Defines a Base class for declarative models which will be used to create database tables
- Provides a
get_db
function to manage database connections
We're now ready to define our database models and API endpoints.
Defining Models and Schemas
Let's start by creating an API for managing a tech conference system. We'll need database models and Pydantic schemas for talks and speakers.
Create a models.py
file for SQLAlchemy models and relationships:
This defines Speaker
and Talk
models with their respective fields and relationships. The speaker_id
field in the Talk
model establishes a foreign key relationship with the Speaker
model using SQLAlchemy's ForeignKey
construct.
Now, create a schemas.py
file for Pydantic models with data validation:
Here we define Pydantic models for creating and returning speaker and talk data.
The TalkCreate
model includes a speaker_id
field for associating talks with speakers. The SpeakerWithTalks
model extends the Speaker
model to include a list of talks. The orm_mode = True
configuration enables automatic data conversion between SQLAlchemy models and Pydantic models.
These models will be used to validate incoming data and serialize outgoing data in our API endpoints instead of manually handling data conversion.
Creating API Endpoints
Now, let's create our FastAPI application with CRUD operations for speakers and talks. Create a main.py
file:
This code defines endpoints for:
- Creating and retrieving speakers at
/speakers/
- Retrieving a specific speaker with their talks at
/speakers/{speaker_id}
- Creating and retrieving talks at
/talks/
- Retrieving a specific talk at
/talks/{talk_id}
Each endpoint uses dependency injection to get a database session, ensuring efficient connection management.
Pagination is supported for the read_speakers
and read_talks
endpoints using the skip
and limit
parameters to avoid loading large datasets at once.
Running the API
To run the API, use the following command:
This starts the Uvicorn server with hot-reloading enabled for development.
By default, the API will be available on port 8000. You can access the API documentation at http://127.0.0.1:8000/docs
or http://127.0.0.1:8000/redoc
.
Your database tables will be created automatically when you run the API for the first time thanks to the models.Base.metadata.create_all(bind=engine)
line in main.py
. You can check your database to see the tables using the Neon console.
Testing the API
You can test the API using tools like curl
, Postman
, or even via the /docs
endpoint provided by FastAPI directly via your browser.
Let's test this out using httpie
, a command-line HTTP client:
-
Start by creating a speaker:
You should see a response with the created speaker data.
-
Next, create a talk associated with the speaker:
This will create a talk associated with the speaker created earlier and return the talk data.
-
Retrieve all speakers:
This endpoint will return a list of all speakers in the database.
-
Retrieve a specific speaker with talks:
This will return the speaker data along with any talks associated with them.
-
Retrieve all talks:
-
Retrieve a specific talk:
You can modify these requests to test other endpoints and functionalities.
Dockerizing the Application
In many cases, you may want to containerize your FastAPI application for deployment. Here's how you can create a Dockerfile for your project:
This Dockerfile uses a slim Python image, installs dependencies from a requirements.txt
file, copies the project files, and runs the Uvicorn server.
To build a new Docker image, run the following command in your project directory:
You can then run the Docker container with:
This will start the FastAPI application in a Docker container, accessible on port 8000 of your host machine.
You need to make sure that your .env
file is not included in the Docker image. Instead, you can pass the environment variables as arguments when running the container.
Performance Considerations
-
Database Indexing: We've added indexes to frequently queried fields (
id
,name
,title
) in our models. This improves query performance. To learn more about indexing, refer to the Neon documentation. -
Pagination: The
read_speakers
andread_talks
endpoints includeskip
andlimit
parameters for pagination, preventing the retrieval of unnecessarily large datasets. -
Dependency Injection: By using
Depends(get_db)
, we make sure that database connections are properly managed and closed after each request. This prevents connection leaks and improves performance. -
Pydantic Models: Using Pydantic for request and response models provides automatic data validation and serialization, reducing the need for manual checks.
-
Relationships: We've used SQLAlchemy relationships to efficiently load related data (speakers and their talks) in a single query.
Conclusion
In this guide, we've built a simple API for managing a tech conference system using FastAPI, Pydantic, and Neon Postgres.
This combination provides a very good foundation for building scalable and efficient web services. FastAPI's speed and ease of use, combined with Pydantic's powerful data validation and Neon's serverless Postgres, make for a formidable tech stack.
As a next step, you can extend the API with more features like authentication, authorization, and advanced query capabilities. You can check out the Implementing Secure User Authentication in FastAPI using JWT Tokens and Neon Postgres guide for adding JWT-based authentication to your API.
Additional Resources
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. Users on paid plans can open a support ticket from the console. For more details, see Getting Support.