Build Your Own Forum with FastAPI: Step 1 - A Minimal Forum
Takashi Yamamoto
Infrastructure Engineer · Leapcell

There are already many forum products on the market, but are you still frustrated because none of them meet your unique needs? If so, why not build a forum from scratch yourself?
Don't be intimidated by giant forum SaaS platforms like Discourse; building a forum isn't as difficult as it seems.
In the upcoming series of articles, we will guide you step-by-step from scratch to build a fully functional, modern forum website using the popular Python web framework, FastAPI.
This tutorial series is tailored for beginners. By the end of this first article, you will have a runnable mini-forum, just like the one shown below:
Without further ado, let's get started:
Step 1: Environment Setup
First, let's prepare the development environment.
Create a Project Directory and Virtual Environment
Create a dedicated folder for the project and create a virtual environment within it.
For simplicity, we'll use Python's built-in venv
module. There are many other great virtual environment tools, such as poetry
, which you can explore on your own.
# Create and enter the project directory mkdir fastapi-forum cd fastapi-forum # Create the virtual environment python3 -m venv venv # Activate the virtual environment # Windows: # venv\Scripts\activate # macOS / Linux: source venv/bin/activate
After successful activation, you will see (venv)
prepended to your command line prompt.
Install FastAPI and Uvicorn
Next, we'll install the core libraries needed for this article: fastapi
and uvicorn
.
fastapi
: The framework itself.uvicorn
: An ASGI server used to run our FastAPI application.
pip install fastapi "uvicorn[standard]"
"uvicorn[standard]"
installs uvicorn along with some recommended dependencies for optimal performance.
Step 2: "Hello, Forum!" Get the FastAPI App Running
With the environment ready, let's write our first line of FastAPI code. Create a file named main.py
in the fastapi-forum
directory and add the following content:
main.py
from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"message": "Hello, Forum!"}
What does this code do?
- It creates an instance of
FastAPI
and names itapp
. @app.get("/")
is a decorator. It tells FastAPI that the functionread_root
below will handleGET
requests coming to the path/
.- When a request hits the root path, the function returns a Python dictionary, which FastAPI automatically converts into a JSON response.
Next, run the application from your terminal:
uvicorn main:app --reload
main
: Refers to themain.py
file.app
: Refers to theFastAPI
instanceapp
you created inmain.py
.--reload
: This is a very useful parameter that makes the server restart automatically after code changes.
Now, open your browser and navigate to http://127.0.0.1:8000
. You will see:
{ "message": "Hello, Forum!" }
Congratulations! Your first FastAPI application is now running successfully!
Step 3: Define the Core Data Structure
Our forum is for publishing posts, so we need a clear data structure to define what a "post" looks like. FastAPI recommends using Pydantic
for data definition and validation. It's built into FastAPI and is very powerful.
Let's define a Post
model in main.py
.
main.py
(Updated)
from fastapi import FastAPI from pydantic import BaseModel from typing import List # 1. Define the data model class Post(BaseModel): id: int title: str content: str app = FastAPI() # 2. Use a list as an in-memory database # Note: This is for demonstration only. Data will be lost upon server restart! db: List[Post] = [ Post(id=1, title="What is FastAPI?", content="A modern, high-performance Python web framework..."), Post(id=2, title="Introduction to Pydantic", content="Pydantic is a library for data validation and settings management..."), ] @app.get("/") def read_root(): return {"message": "Welcome to my forum!"} # Subsequent APIs will be added here...
We created a Post
class that inherits from pydantic.BaseModel
. We defined that a post should have three fields: id
(integer), title
(string), and content
(string).
We also created a list named db
and pre-populated it with two Post
objects to simulate our database.
Step 4: Implement the Core APIs
A basic forum needs two features: viewing posts and creating posts. Let's implement the corresponding API endpoints.
1. Get All Posts
We need an endpoint that returns all the posts in our db
list. Add the following code to main.py
:
main.py
(Continued)
... # Previous code remains unchanged # 3. API to get the list of posts @app.get("/api/posts", response_model=List[Post]) def get_posts(): return db
@app.get("/api/posts")
: We define a new path/api/posts
that handlesGET
requests.response_model=List[Post]
: This tells FastAPI that the response body for this endpoint will be a list ofPost
objects. FastAPI uses this for data validation, conversion, and clear documentation in the API docs.
2. Create a New Post
Next is the endpoint for creating a new post.
First, install python-multipart
to support handling form data:
pip install python-multipart
main.py
(Continued)
# ... Previous code remains unchanged # 4. API to create a new post @app.post("/api/posts", response_model=Post) def create_post(title: str = Form(...), content: str = Form(...)): new_id = len(db) + 1 new_post = Post( id=new_id, title=title, content=content ) db.append(new_post) return new_post
The parameter format title: str = Form(...)
tells FastAPI to extract the data from form fields.
Why are the input/output formats form fields? Because we will later create an HTML page where users can submit post content through a form.
Step 5: A Simple Interactive Page
A pure API can't really be called a forum. We can use FastAPI's HTMLResponse
to quickly create a usable HTML page, allowing users to create and view posts directly in their browser.
We will create a new path GET /posts
to display this page.
main.py
(Final Complete Version)
from fastapi import FastAPI, Form from fastapi.responses import HTMLResponse, RedirectResponse from pydantic import BaseModel from typing import List # --- Data Models --- class Post(BaseModel): id: int title: str content: str # --- In-Memory Database --- db: List[Post] = [ Post(id=1, title="What is FastAPI?", content="A modern, high-performance Python web framework..."), Post(id=2, title="Introduction to Pydantic", content="Pydantic is a library for data validation and settings management..."), ] app = FastAPI() # --- HTML Template --- def generate_html_response(): posts_html = "" for post in reversed(db): # Show new posts at the top posts_html += f""" <div style="border: 1px solid #ccc; padding: 10px; margin-bottom: 10px;"> <h3>{post.title} (ID: {post.id})</h3> <p>{post.content}</p> </div> """ html_content = f""" <html> <head> <title>My FastAPI Forum</title> <style> body {{ font-family: sans-serif; margin: 2em; }} input, textarea {{ width: 100%; padding: 8px; margin-bottom: 10px; box-sizing: border-box; }} button {{ padding: 10px 15px; background-color: #007BFF; color: white; border: none; cursor: pointer; }} button:hover {{ background-color: #0056b3; }} </style> </head> <body> <h1>Welcome to My Forum</h1> <h2>Create a New Post</h2> <form action="/api/posts" method="post"> <input type="text" name="title" placeholder="Post Title" required><br> <textarea name="content" rows="4" placeholder="Post Content" required></textarea><br> <button type="submit">Post</button> </form> <hr> <h2>Post List</h2> {posts_html} </body> </html> """ return HTMLResponse(content=html_content, status_code=200) # --- Routes --- @app.get("/", response_class=RedirectResponse) def read_root(): # Redirect the root path to our view page return "/posts" # Route to display the page @app.get("/posts", response_class=HTMLResponse) async def view_posts(): return generate_html_response() @app.post("/api/posts") def create_post(title: str = Form(...), content: str = Form(...)): new_id = len(db) + 1 new_post = Post( id=new_id, title=title, content=content ) db.append(new_post) # Redirect back to the main page after posting for a refresh effect return RedirectResponse(url="/posts", status_code=303)
We use the generate_html_response
function to dynamically generate a complete HTML page containing the form and the post list. While primitive, it's perfectly sufficient for this stage.
GET /posts
will directly return the generated HTML page, allowing users to see the forum interface when they visit /posts
. Additionally, the root path /
is redirected to /posts
, so users visiting the root URL are automatically taken to the forum page.
You might notice that GET /api/posts
has been removed. This is because we no longer need a separate API to get the post list; the page reads the data directly from the in-memory db
.
We have also modified the logic for POST /api/posts
. Instead of returning a Post
object, it now redirects back to the /posts
page so that users can see the updated post list immediately after submission.
Run the Forum
Now, make sure your uvicorn server is still running. Refresh or revisit http://127.0.0.1:8000
, and you will see the forum page with existing posts and a form to create new ones.
After entering content into the form and submitting it, you will see your new post appear in the post list.
Deploying the Project Online
A forum is meant to be used by everyone, so just running it locally isn't enough. Next, we can deploy it online.
A simple deployment option is to use Leapcell. It's a web app hosting platform that can host projects in various languages and frameworks, including FastAPI, of course.
Follow the steps below:
- Register an account on the website.
- Commit your project to GitHub. You can refer to GitHub's official documentation for the steps. Leapcell will pull the code from your GitHub repository later.
- Click "Create Service" on the Leapcell page.
- After choosing your FastAPI repo, you'll see Leapcell has auto-populated the necessary configurations.
- Click "Submit" at the bottom to deploy. The deployment will complete quickly and return you to the deployment homepage. Here we can see that Leapcell has provided a domain. This is the online address of your blog.
Conclusion
In just a few short steps, we have built a forum prototype with the most essential features from scratch using FastAPI.
This forum is still very incomplete. For example, as soon as the server restarts, all the new posts disappear. This is obviously unacceptable.
In the next article, we will introduce a real database to our forum to enable persistent data storage.