In this tutorial, we will create a basic blog app using FastAPI for the backend, HTML and CSS for the frontend, and a JSON file for performing basic CRUD (Create, Read, Update, Delete) operations.
FastAPI is a modern web framework for building APIs with Python, which is known for its simplicity, speed, and built-in support for asynchronous operations.
Below Implementation would looks like this :
Before getting started, ensure you have the following installed:
To install FastAPI and Uvicorn, you can use pip:
pip install fastapi uvicorn python-multipart
Here's how the project will be structured:
/blog_app ├── static │ └── style.css ├── templates │ ├── index.html │ ├── post.html │ ├── create_post.html ├── blog.json ├── main.py
Create a main.py file which will contain the FastAPI application.
from fastapi import FastAPI, Request, Form from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates import json import os app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") # Load or initialize blog data BLOG_FILE = "blog.json" if not os.path.exists(BLOG_FILE): with open(BLOG_FILE, "w") as f: json.dump([], f) def read_blog_data(): with open(BLOG_FILE, "r") as f: return json.load(f) def write_blog_data(data): with open(BLOG_FILE, "w") as f: json.dump(data, f) @app.get("/", response_class=HTMLResponse) async def home(request: Request): blogs = read_blog_data() return templates.TemplateResponse("index.html", {"request": request, "blogs": blogs}) @app.get("/post/{post_id}", response_class=HTMLResponse) async def read_post(request: Request, post_id: int): blogs = read_blog_data() post = blogs[post_id] if 0 <= post_id < len(blogs) else None return templates.TemplateResponse("post.html", {"request": request, "post": post}) @app.get("/create_post", response_class=HTMLResponse) async def create_post_form(request: Request): return templates.TemplateResponse("create_post.html", {"request": request}) @app.post("/create_post") async def create_post(title: str = Form(...), content: str = Form(...)): blogs = read_blog_data() blogs.append({"title": title, "content": content}) write_blog_data(blogs) return RedirectResponse("/", status_code=303) @app.post("/delete_post/{post_id}") async def delete_post(post_id: int): blogs = read_blog_data() if 0 <= post_id < len(blogs): blogs.pop(post_id) write_blog_data(blogs) return RedirectResponse("/", status_code=303)
In the templates folder, create the following HTML files:
index.html
This file will list all the blog posts.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Blog App</title> <link rel="stylesheet" href="/static/style.css"> </head> <body> <h1>Blog Posts</h1> <a href="/create_post">Create New Post</a> <div> {% for post in blogs %} <div class="post"> <h2>{{ post.title }}</h2> <p>{{ post.content[:100] }}...</p> <a href="/post/{{ loop.index0 }}">Read more</a> <form method="post" action="/delete_post/{{ loop.index0 }}"> <button type="submit">Delete</button> </form> </div> {% endfor %} </div> </body> </html>
post.html
This file will display the full content of a blog post.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ post.title }}</title> <link rel="stylesheet" href="/static/style.css"> </head> <body> <h1>{{ post.title }}</h1> <p>{{ post.content }}</p> <a href="/">Back to Home</a> </body> </html>
create_post.html
This file will contain the form for creating a new post.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Create a New Post</title> <link rel="stylesheet" href="/static/style.css"> </head> <body> <h1>Create a New Post</h1> <form method="post" action="/create_post"> <label for="title">Title</label> <input type="text" name="title" id="title" required> <label for="content">Content</label> <textarea name="content" id="content" required></textarea> <button type="submit">Create</button> </form> <a href="/">Back to Home</a> </body> </html>
In the static folder, create a style.css file to add some basic styling.
body { font-family: Arial, sans-serif; padding: 20px; background-color: #f0f0f0; } h1 { color: #333; } a { text-decoration: none; color: #0066cc; } .post { background-color: #fff; padding: 10px; margin-bottom: 15px; border-radius: 5px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } button { background-color: #ff4d4d; border: none; padding: 5px 10px; color: white; border-radius: 3px; cursor: pointer; } button:hover { background-color: #ff1a1a; } input, textarea { width: 100%; padding: 8px; margin-bottom: 10px; }
Now that everything is set up, run the FastAPI application using Uvicorn.
uvicorn main:app --reload
Visit http://127.0.0.1:8000 in your browser, and you should see the blog homepage.
As an assignment, you can use a Database ?️ instead of just JSON to create a full-stack web app.
With a database, you can add more features ?, improve performance ?, and enhance the overall UI/UX ? for a richer user experience.
That's all for this blog! Stay tuned for more updates and keep building amazing apps! ?✨
The above is the detailed content of Building a Simple Blog App Using FastAPI, HTML, CSS, and JSON. For more information, please follow other related articles on the PHP Chinese website!