In this tutorial, I will guide you through the process of creating a Video Membership Web App from scratch using Python, NoSQL, and FastAPI. FastAPI is a modern, fast (high-performance), web framework for building APIs with Python. NoSQL databases are becoming increasingly popular for building web applications due to their flexibility and scalability.
We will be using MongoDB as our NoSQL database. MongoDB is a document-oriented NoSQL database that stores data in flexible, JSON-like documents. It is highly scalable and can handle large amounts of data efficiently.
By the end of this tutorial, you will have a fully functional Video Membership Web App where users can sign up, log in, view and upload videos, and subscribe to different membership plans.
Prerequisites:
- Basic understanding of Python
- Familiarity with API development concepts
- Basic knowledge of MongoDB
- Install Python on your machine
- Install MongoDB on your machine
- Install FastAPI using pip
Let’s get started!
Step 1: Setting up the project
Create a new directory for your project and navigate to it in the terminal. Create a new Python virtual environment using the following command:
python -m venv venv
Activate the virtual environment using:
- For Windows:
venvScriptsactivate
- For macOS/Linux:
source venv/bin/activate
Install FastAPI, Pydantic, and Motor using pip:
pip install fastapi uvicorn pydantic motor
Step 2: Setting up MongoDB
Start MongoDB on your machine using the following command:
mongod
Create a new database for your project using the MongoDB shell:
mongo
use video_membership
exit
Step 3: Create a FastAPI app
Create a new Python file named main.py
in your project directory and add the following code:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"Hello": "World"}
Run the FastAPI app using Uvicorn:
uvicorn main:app --reload
Navigate to http://localhost:8000
in your browser to see the "Hello World" message.
Step 4: Create models for users and videos
Create a new Python file named models.py
in your project directory and add the following code:
from pydantic import BaseModel
from bson import ObjectId
class User(BaseModel):
id: ObjectId
username: str
email: str
password: str
class Video(BaseModel):
id: ObjectId
title: str
description: str
url: str
Step 5: Create CRUD endpoints for users and videos
Update the main.py
file with the following code to create CRUD endpoints for users and videos:
from fastapi import FastAPI, HTTPException
from typing import List
from models import User, Video
from motor.motor_asyncio import AsyncIOMotorClient
app = FastAPI()
client = AsyncIOMotorClient()
db = client.video_membership
@app.post("/users/", response_model=User)
async def create_user(user: User):
result = await db.users.insert_one(user.dict(exclude_unset=True))
user.id = result.inserted_id
return user
@app.get("/users/", response_model=List[User])
async def get_users():
users = await db.users.find().to_list(1000)
return users
@app.post("/videos/", response_model=Video)
async def create_video(video: Video):
result = await db.videos.insert_one(video.dict(exclude_unset=True))
video.id = result.inserted_id
return video
@app.get("/videos/", response_model=List[Video])
async def get_videos():
videos = await db.videos.find().to_list(1000)
return videos
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Step 6: Testing the CRUD endpoints
Run the FastAPI app using Uvicorn and navigate to http://localhost:8000/docs
in your browser to see the Swagger UI documentation. You can test the CRUD endpoints for users and videos from the Swagger UI.
Step 7: Implement user authentication
Update the main.py
file with the following code to implement user authentication using JSON Web Tokens (JWT):
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import OAuth2PasswordBearer
from jwt import encode, decode, ExpiredSignatureError
from datetime import datetime, timedelta
from passlib.context import CryptContext
from models import User, Video
from motor.motor_asyncio import AsyncIOMotorClient
app = FastAPI()
client = AsyncIOMotorClient()
db = client.video_membership
SECRET_KEY = "supersecretkey"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_access_token(data: dict):
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode = data.copy()
to_encode.update({"exp": expire})
return encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload["sub"]
user = await db.users.find_one({"username": username})
if user is None:
raise HTTPException(status_code=401, detail="Invalid credentials")
return user
except ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token has expired")
@app.post("/token")
async def login_for_access_token(user: User):
user = await db.users.find_one({"username": user.username})
if user is None or not pwd_context.verify(user.password, user.password):
raise HTTPException(status_code=401, detail="Invalid username or password")
return {"access_token": create_access_token({"sub": user.username})}
@app.post("/users/", response_model=User)
async def create_user(user: User):
hashed_password = pwd_context.hash(user.password)
user.password = hashed_password
result = await db.users.insert_one(user.dict(exclude_unset=True))
user.id = result.inserted_id
return user
Step 8: Add video upload and subscription endpoints
Update the main.py
file with the following code to add video upload and subscription endpoints:
@app.post("/videos/", response_model=Video)
async def create_video(video: Video, current_user: User = Depends(get_current_user)):
result = await db.videos.insert_one(video.dict(exclude_unset=True))
video.id = result.inserted_id
return video
@app.post("/subscribe/")
async def subscribe_to_membership(user: User, current_user: User = Depends(get_current_user)):
# implement subscription logic here
pass
Step 9: Testing the Video Membership Web App
Run the FastAPI app using Uvicorn and navigate to http://localhost:8000/docs
in your browser to test the Video Membership Web App.
Congratulations! You have successfully created a Video Membership Web App from scratch using Python, NoSQL, and FastAPI. You can further enhance the app by adding features like video playback, user profiles, payment integration, and more. Feel free to explore FastAPI’s documentation and MongoDB’s documentation for more advanced features and capabilities. Happy coding!
Let's do this!
Code: https://github.com/codingforentrepreneurs/video-membership
Chapters
00:00:00 Welcome
00:05:27 Requirements
00:06:51 Setup VSCode & Python Virtual Environment
00:12:12 Hello World with FastAPI
00:18:58 Picking a Database
00:24:56 Create our NoSQL Database with AstraDB
00:27:48 Basic AstraDB Configuration for FastAPI
00:35:54 Configuration & Environment Variables
00:43:30 Create our User model with Python & Cassandra
00:51:08 Sync Cassandra Tabels via FastAPI On Startup
00:58:40 Create a user via shell
01:02:05 List Stored Values on API Endpoint
01:05:15 User Create Method & Email Validation
01:13:12 Security & Password Hashing
01:22:45 Interactive Notebook to Analyze New Features
01:32:18 Automated Tests
01:50:25 Jinja Templates to Render HTML
02:00:00 Jinja Template Inheritance & More
02:06:44 FastAPI Forms FastAPI Login & Sign Up Forms
02:15:16 User Data Validation with pydantic
02:26:10 Implement pydantic Data Validation
02:35:44 Pydantic Valid Data or Error Method
02:44:06 Experiment with JWT Tokens
02:58:02 Implement Auth Methods for JWT Tokens
03:07:53 Shortcut Method for Rendering Jinja Templates
03:19:53 Using Cookies & httponly within FastAPI
03:27:54 Login & Set JWT
03:37:09 Redirect Shortcut
03:41:53 Login Required Decorator
03:52:36 Render a template for HTTP Errors
04:04:24 Authentication Middleware Backend
04:20:50 Video Model
04:27:57 YouTube Video ID Extraction
04:35:17 Notebook to Verify Video Add Feature
04:41:51 Custom Exception Classes for Videos
04:46:21 Routers for Sub Modules in FastAPI
04:52:51 Video Create Schema
05:02:59 Video Create View
05:06:00 Video Create View Form
05:18:52 Video List View & Title Field
05:29:43 Dynamic URL Routing & Video Detail View
05:40:50 Render Video on Detail Page
05:46:56 The YouTube JavaScript Player
06:34:13 Video Watch Events Endpoint in FastAPI
06:45:17 Watch Event Model
06:55:30 Drop Table from Cassandra Database via Notebook
07:03:45 More Watch Event Data
07:09:24 Pydantic Model for Watch Event Data
07:17:40 Watch Event Router
07:22:32 Get Video Resume Time
07:30:07 Playlist Model & Cassandra List Column
07:34:42 Playlist Tests in Notebooks
07:45:25 Playlist Routing & Templates
07:55:36 HTMX, FastAPI, & Jinja
08:04:07 Use HTMX to Handle Form Data
08:16:36 Get or Create Video for Playlists
08:24:49 Playlist Routers for Handling Video Additions
08:37:23 Playlist Video Schema
08:48:58 Remove Playlist Item via HTMX
09:01:13 Edit or Remove Video
09:11:04 Edit or Remove Video via HTMX
09:27:16 Add Bootstrap & Improve Usability
10:07:19 Login Required HTMX Redirect Header
10:11:10 Logout View
10:18:58 Prepare our Search Index
10:33:00 Implement Algolia Client & API
10:41:43 Update Search Index
10:49:46 Search View & Update Index Method
11:03:25 Thank you and next steps
Hello , I recently started this and got error 35:54 Configuration & environment variables …… error message …. class Settings(BaseSettings):
keyspace: str = Field(…, env='ASTRADB_KEYSPACE'). The error message …pydantic_core._pydantic_core.ValidationError: 2 validation errors for Settings
keyspace
Field required [type=missing, input_value={'astradb_keyspace': 'example_keyspace'}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.9/v/missing
astradb_keyspace
Extra inputs are not permitted [type=extra_forbidden, input_value='example_keyspace', input_type=str]
For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden… This I corrected in the statement – keyspace: str = Field(…, alias='ASTRADB_KEYSPACE')
Watched it in one go this sunday😂 way better than any weekend stupid plans
if you are having issues with UnauthenticatedUser not returning false for request.user.is_authenticated you can modify the JWTCookieBackend class like below
class JWTCookieBackend(AuthenticationBackend):
async def authenticate(self, request):
session_token = request.cookies.get("session_id")
user_data = auth.verify_user_id(session_token)
if user_data is None:
# roles = ['anon']
return
user_id = user_data.get("user_id")
roles = ["authenticated"]
return AuthCredentials(roles), SimpleUser(user_id)
A want to make a membership website when users can add thier city coures regestred in and people can search people in same course or city how can do this i am stuck help you said if you have question Ask it
are we going to use any kind of API?
if yes is it free
Thank you very much! I've learned a lot!
for autoplay you need to put in muted as well, then it will work
Thank you!
AnyOne Help
File "C:UsersarifVideoDeltaappmain.py", line 69, in login_post_view
File "pydanticmain.py", line 339, in pydantic.main.BaseModel._init_
File "pydanticmain.py", line 1102, in pydantic.main.validate_model
File "C:UsersarifVideoDeltaappusersschemas.py", line 25, in validate_user
user_obj = auth.authenticate(email, password)
File "C:UsersarifVideoDeltaappusersauth.py", line 14, in authenticate
if not user_obj.verify_password(password):
AttributeError: 'NoneType' object has no attribute 'verify_password'
please more fastapi tutorials, maybe make one premium course with stripe, social login, htmx and I pay 195$ ❤
Django version please
how about a payment gateway?
Wow this is something great. Thanks a lot
This one is still way over my Head.. BUT Already thank you for the huge Tutorial and .. See you in a bit! (okey, so what was a variable again..? haha jk) .. learning..
Awesome in-depth and well-explained tutorial!
Hello Justin, I'm trying to write unit test. I'm having challenges mocking the database and altering the keyspace name to enhance testing.
Any help pls???
Thanks
stunning content, and yet for free, unbelievable!!
Learning a lot, thanks for existing 🙂
~still 2 hours in it, cant wait to get the full content..
this is crazy