Skip to content

KevinSilvester/mern-movie

Repository files navigation

MERN Stack Movie Website

Demo at https://moviedb.kevins.site

A full-stack application built using:

  • TypeScript
  • Rust
  • Bun
  • React
  • Axum
  • MongoDB

Screenshots

UI design heavily inspired by https://anilist.co/search/anime

Screen 3 Screen 4 Screen 5 Screen 6 Mobile Screen 1 Mobile Screen 2 Mobile Screen 3 Mobile Screen 4 Mobile Screen 5 Mobile Screen 6


Project Structure

  • api-server:

  • client-app:

    • The client-side website built with ReactJS
  • client-server:

    • Serves the static files generated after the client-app build process at https://moviedb.kevins.site
    • Written in Rust using Axum web-framework and Tokio async runtime

Features

  • Create,Read,Update and Delete movies (CRUD operation)
  • Full database reset with a daily limit
  • Responsive UI with light and dark theme
  • Fuzzy search, sort, filter (using URLQueryParams)
  • Dynamic import/code splitting for smaller bundle size
  • Custom selection component (not yet keyboard accessible)
  • Loading skeleton for images, text and iframes
  • Fallback image for missing poster links
  • Extra info (i.e. Banner, YouTube trailer, IMDb link)

Quick Start

Requirements
  • bun (minimum v1.2.x)
  • rust toolchain (minimum v1.89.x)
  • MongoDB Atlas (required for search aggregation)
  • TheMovieDB API key (More Info)
Setup
  1. Create MongoDB Atlas Account
    After account is made...

    • Create a New Project
    • Create a new Database Cluster in that project
    • Add a new Collection called movies to database
    • Create a Search Index using index definition (See mongo-index-def.json)
  2. Install Dependencies

    # client-app dependenices
    bun install
  3. Make a .env file in the ./api-server directory

    Example: .env.example

    # Cloudflare secrets to upload and delete images from R2 storage bucket
    CLOUDFLARE_ACCOUNT_ID=
    CLOUDFLARE_ACCESS_KEY_ID=
    CLOUDFLARE_SECRET_ACCESS_KEY=
    CLOUDFLARE_R2_BUCKET=
    
    # Mongodb Atlas connection details
    MONGO_CONNECTION_URI=mongodb+srv://<USERNAME>:<PASSWORD>@<PROJECT_NAME>.???.???.???
    MONGO_DB_NAME=
    MONGO_SEARCH_INDEX=
    
    # TheMovieDB Access Token for request `Authorization` header
    TMDB_ACCESS_TOKEN=
    
    # A custom api token to bypass the limit on number of request on the `reset` endpoint
    # can be generated with `openssl rand -hex 128`
    MOVIEDB_API_ADMIN_TOKEN=
  4. Start the api-server:

    The api-server uses an in memory cache for responses from TMDB. This primarily to speed up database the reset operation where some details for a movie are retrieved from TMDB.

    Since the cache is in-memory, it gets wiped when you have restart the server, which happens a lot when developing.

    To counter this issue, there is an optional build feature tmdb-cache-file for the api-server crate. When this feature is present, responses from TMDB will be cached in-memory AND the will be written to a binary file. This allows for subsequent restarts of the server with tmdb-cache-file feature present, to read the binary files before the server starts, so that the cache is pre-populated.

    # to start the server locally with in-memory caching
    cd api-server && cargo run
    # to start the server with file and in-memory caching
    cd api-server && cargo run --features tmdb-cache-file

    It is also possible to select the logging formats, logging level and port number the server runs on in the start command.

    # Running this command will:
    # 1. Enable the 'tmdb-cache-file' build feature
    # 2. Set the port number of the server to 4000
    # 3. Set the format of the logged text to json
    # 4. Set the log level of the server to 'info' (the lowest level is 'trace')
    cargo run --features tmdb-cache-file -- --port 4000 --log-format json --log-level info

    You can see all the available runtime options by running:

    cargo run -- --help
  5. Start the client-app

    # to start client-app
    cd client-app && bun run dev
  6. Start the client-server (Optional)

    Before running this server, the client-app must be built and bundled by running:

    cd client-app && bun run build

    If successful, this should generate the bundled production output of the client-app in the location ./client-app/dist/.

    Once built, start the server by providing the relative or absolute path to the static files the server should serve:

    cd client-server
    cargo run -- ../client-app/dist
    
    # the 'client-server' has similar option to api-server
    # to select the server port
    cargo run -- --port 3000 ../client-app/dist

Key Dependencies/Packages

  • Both servers
    axum Web framework that focuses on ergonomics and modularity
    clap A simple to use, efficient, and full-featured Command Line Argument Parser
    mimalloc Performance and security oriented drop-in allocator
    tokio An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications.
    serde A generic serialization/deserialization framework
    validator Request validation
  • api-server
    aws-skd-s3 For file upload to Cloudflare R2
    bincode A binary serialization / deserialization strategy for transforming structs into bytes and vice versa! (For caching to file when using tmdb-file-cache feature)
    moka A fast and concurrent cache library inspired by Java Caffeine
    mongodb The official MongoDB driver for Rust
    mongodb The official MongoDB driver for Rust
  • client-app
    TypeScript Type safe code
    Zod Schema based validation
    Axios HTTP client for browser and node.js
    Prettier Code formatter
    Eslint Code Linting
    ViteJs A rapid development tool
    React Front-end JavaScript library
    React-Router Client-side routing with React
    Zustand A bear-bone state-management tool
    React Query Caching, managing and syncing asynchronous data
    Framer Motion For smooth animated transitions/interactions
    Popper.js Popover positioning engine
    React-Hook-Form Performant form validation
    React-Toastify Toast notification in React
    Filepond JavaScript file upload library