Build a Video Membership Web App with Python, NoSQL, & FastAPI from the Ground Up

Posted by


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!

0 0 votes
Article Rating
36 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
@CodingEntrepreneurs
1 month ago

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

@skn4
1 month ago

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')

@amitavasengupta5580
1 month ago

Watched it in one go this sunday😂 way better than any weekend stupid plans

@HamzaKhan-wi9kb
1 month ago

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)

@mit8392
1 month ago

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

@darkspirit4531
1 month ago

are we going to use any kind of API?
if yes is it free

@excels6277
1 month ago

Thank you very much! I've learned a lot!

@tariq.rashid
1 month ago

for autoplay you need to put in muted as well, then it will work

@jkmaciel
1 month ago

Thank you!

@aarifhussain9751
1 month ago

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'

@streamocu2929
1 month ago

please more fastapi tutorials, maybe make one premium course with stripe, social login, htmx and I pay 195$ ❤

@The_ProBoys
1 month ago

Django version please

@harshAmiya
1 month ago

how about a payment gateway?

@RohitSaini52945
1 month ago

Wow this is something great. Thanks a lot

@maxfrischdev
1 month ago

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..

@impfect
1 month ago

Awesome in-depth and well-explained tutorial!

@princewillinyang5993
1 month ago

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???

@pitchhome48
1 month ago

Thanks

@renancatan
1 month ago

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..

@EmptyNonsens
1 month ago

this is crazy